home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Programming / fpc / compiler / rai386.pas < prev    next >
Pascal/Delphi Source File  |  1998-09-24  |  140KB  |  3,485 lines

  1. {
  2.     $Id: rai386.pas,v 1.2.2.1 1998/05/25 22:58:50 carl Exp $
  3.     Copyright (c) 1997-98 by Carl Eric Codere
  4.  
  5.     Does the parsing process for the intel styled inline assembler.
  6.  
  7.     This program is free software; you can redistribute it and/or modify
  8.     it under the terms of the GNU General Public License as published by
  9.     the Free Software Foundation; either version 2 of the License, or
  10.     (at your option) any later version.
  11.  
  12.     This program is distributed in the hope that it will be useful,
  13.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.     GNU General Public License for more details.
  16.  
  17.     You should have received a copy of the GNU General Public License
  18.     along with this program; if not, write to the Free Software
  19.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  
  21.  ****************************************************************************
  22. }
  23. Unit Rai386;
  24.  
  25. {**********************************************************************}
  26. { WARNING                                                              }
  27. {**********************************************************************}
  28. {  Any modification in the order or removal of terms in the tables     }
  29. {  in i386.pas and intasmi3.pas will BREAK the code in this unit,      }
  30. {  unless the appropriate changes are made to this unit. Addition      }
  31. {  of terms though, will not change the code herein.                   }
  32. {**********************************************************************}
  33.  
  34. {--------------------------------------------------------------------}
  35. { LEFT TO DO:                                                        }
  36. {--------------------------------------------------------------------}
  37. { o Add support for floating point opcodes.                          }
  38. { o Handle module overrides also... such as crt.white or             }
  39. {    crt.delay and local typed constants.                            }
  40. { o Handle label references                                          }
  41. { o Add support for TP styled segment overrides, when the opcode     }
  42. {    table will be completed.                                        }
  43. { o Add imul,shld and shrd support with references and CL            }
  44. {    i386.pas requires to be updated to do this.                     }
  45. { o Support for (* *) tp styled comments, this support should be     }
  46. {   added in asmgetchar in scanner.pas (it cannot be implemented     }
  47. {   here without causing errors such as in :                         }
  48. {   (* "openbrace" AComment *)                                       }
  49. {   (presently an infinite loop will be created if a (* styled       }
  50. {    comment is found).                                              }
  51. { o Bugfix of ao_imm8s for IMUL. (Currently the 3 operand imul will  }
  52. {   be considered as invalid because I use ao_imm8 and the table     }
  53. {   uses ao_imm8s).                                                  }
  54. {--------------------------------------------------------------------}
  55.  
  56. Interface
  57.  
  58. uses
  59.   tree,i386;
  60.  
  61.    function assemble: ptree;
  62.  
  63. const
  64.  { this variable is TRUE if the lookup tables have already been setup  }
  65.  { for fast access. On the first call to assemble the tables are setup }
  66.  { and stay set up.                                                    }
  67.  _asmsorted: boolean = FALSE;
  68.  firstreg       = R_EAX;
  69.  lastreg        = R_ST7;
  70.  
  71. type
  72.  tiasmops = array[firstop..lastop] of string[7];
  73.  piasmops = ^tiasmops;
  74.  
  75. var
  76.  { sorted tables of opcodes }
  77.  iasmops: piasmops;
  78.  { uppercased tables of registers }
  79.  iasmregs: array[firstreg..lastreg] of string[6];
  80.  
  81.  
  82. Implementation
  83.  
  84. Uses
  85.   aasm,globals,AsmUtils,strings,hcodegen,scanner,
  86.   cobjects,verbose;
  87.  
  88.  
  89. type
  90.  tinteltoken = (
  91.    AS_NONE,AS_LABEL,AS_LLABEL,AS_STRING,AS_HEXNUM,AS_OCTALNUM,
  92.    AS_BINNUM,AS_COMMA,AS_LBRACKET,AS_RBRACKET,AS_LPAREN,
  93.    AS_RPAREN,AS_COLON,AS_DOT,AS_PLUS,AS_MINUS,AS_STAR,AS_INTNUM,
  94.    AS_SEPARATOR,AS_ID,AS_REGISTER,AS_OPCODE,AS_SLASH,
  95.      {------------------ Assembler directives --------------------}
  96.    AS_DB,AS_DW,AS_DD,AS_END,
  97.      {------------------ Assembler Operators  --------------------}
  98.    AS_BYTE,AS_WORD,AS_DWORD,AS_QWORD,AS_TBYTE,AS_NEAR,AS_FAR,
  99.    AS_HIGH,AS_LOW,AS_OFFSET,AS_SEG,AS_TYPE,AS_PTR,AS_MOD,AS_SHL,AS_SHR,AS_NOT,
  100.    AS_AND,AS_OR,AS_XOR);
  101.  
  102.    tasmkeyword = string[6];
  103. const
  104.    { These tokens should be modified accordingly to the modifications }
  105.    { in the different enumerations.                                   }
  106.    firstdirective = AS_DB;
  107.    lastdirective  = AS_END;
  108.    firstoperator  = AS_BYTE;
  109.    lastoperator   = AS_XOR;
  110.    firstsreg      = R_CS;
  111.    lastsreg       = R_SS;
  112.    { this is a hack to accept all opcodes }
  113.    { in the opcode table.                 }
  114.    { check is done until A_POPFD          }
  115.    { otherwise no check.                  }
  116.    lastop_in_table = A_POPFD;
  117.  
  118.        _count_asmdirectives = longint(lastdirective)-longint(firstdirective);
  119.        _count_asmoperators  = longint(lastoperator)-longint(firstoperator);
  120.        _count_asmprefixes   = 5;
  121.        _count_asmspecialops = 25;
  122.        _count_asmoverrides  = 3;
  123.  
  124.        _asmdirectives : array[0.._count_asmdirectives] of tasmkeyword =
  125.        ('DB','DW','DD','END');
  126.  
  127.        { problems with shl,shr,not,and,or and xor, they are }
  128.        { context sensitive.                                 }
  129.        _asmoperators : array[0.._count_asmoperators] of tasmkeyword = (
  130.         'BYTE','WORD','DWORD','QWORD','TBYTE','NEAR','FAR','HIGH',
  131.         'LOW','OFFSET','SEG','TYPE','PTR','MOD','SHL','SHR','NOT','AND',
  132.         'OR','XOR');
  133.  
  134.      {------------------ Missing opcodes from std list  ----------------}
  135.        _asmprefixes: array[0.._count_asmprefixes] of tasmkeyword = (
  136.        'REPNE','REPE','REP','REPZ','REPNZ','LOCK');
  137.  
  138.        _asmoverrides: array[0.._count_asmoverrides] of tasmkeyword =
  139.        ('SEGCS','SEGDS','SEGES','SEGSS');
  140.  
  141.        _overridetokens: array[0.._count_asmoverrides] of tregister =
  142.        (R_CS,R_DS,R_ES,R_SS);
  143.  
  144.        _prefixtokens: array[0.._count_asmprefixes] of tasmop = (
  145.        A_REPNE,A_REPE,A_REP,A_REPE,A_REPNE,A_LOCK);
  146.  
  147.        _specialops: array[0.._count_asmspecialops] of tasmkeyword = (
  148.        'CMPSB','CMPSW','CMPSD','INSB','INSW','INSD','OUTSB','OUTSW','OUTSD',
  149.        'SCASB','SCASW','SCASD','STOSB','STOSW','STOSD','MOVSB','MOVSW','MOVSD',
  150.        'LODSB','LODSW','LODSD','LOCK','SEGCS','SEGDS','SEGES','SEGSS');
  151.  
  152.        _specialopstokens: array[0.._count_asmspecialops] of tasmop = (
  153.        A_CMPS,A_CMPS,A_CMPS,A_INS,A_INS,A_INS,A_OUTS,A_OUTS,A_OUTS,
  154.        A_SCAS,A_SCAS,A_SCAS,A_STOS,A_STOS,A_STOS,A_MOVS,A_MOVS,A_MOVS,
  155.        A_LODS,A_LODS,A_LODS,A_LOCK,A_NONE,A_NONE,A_NONE,A_NONE);
  156.      {------------------------------------------------------------------}
  157.        { register type definition table for easier searching }
  158.        _regtypes:array[firstreg..lastreg] of longint =
  159.        (ao_reg32,ao_reg32,ao_reg32,ao_reg32,ao_reg32,ao_reg32,ao_reg32,ao_reg32,
  160.        ao_reg16,ao_reg16,ao_reg16,ao_reg16,ao_reg16,ao_reg16,ao_reg16,ao_reg16,
  161.        ao_reg8,ao_reg8,ao_reg8,ao_reg8,ao_reg8,ao_reg8,ao_reg8,ao_reg8,
  162.        ao_none,ao_sreg2,ao_sreg2,ao_sreg2,ao_sreg3,ao_sreg3,ao_sreg2,
  163.        ao_floatacc,ao_floatacc,ao_floatreg,ao_floatreg,ao_floatreg,ao_floatreg,
  164.        ao_floatreg,ao_floatreg,ao_floatreg);
  165.  
  166.        _regsizes: array[firstreg..lastreg] of topsize =
  167.        (S_L,S_L,S_L,S_L,S_L,S_L,S_L,S_L,
  168.         S_W,S_W,S_W,S_W,S_W,S_W,S_W,S_W,
  169.         S_B,S_B,S_B,S_B,S_B,S_B,S_B,S_B,
  170.         { segment register }
  171.         S_W,S_W,S_W,S_W,S_W,S_W,S_W,
  172.         { can also be S_S or S_T - must be checked at run-time }
  173.         S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,S_Q,S_Q);
  174.  
  175.        _constsizes: array[S_NO..S_S] of longint =
  176.        (0,ao_imm8,ao_imm16,ao_imm32,0,0,0,0,ao_imm32);
  177.  
  178.  
  179.  
  180.  
  181. const
  182.   newline = #10;
  183.   firsttoken : boolean = TRUE;
  184.   operandnum : byte = 0;
  185. var
  186.  { context for SHL,SHR,AND,NOT,OR,XOR operators }
  187.  { if set to true GetToken will return these    }
  188.  { as operators, otherwise will return these as }
  189.  { opcodes.                                     }
  190.  inexpression: boolean;
  191.  p : paasmoutput;
  192.  actasmtoken: tinteltoken;
  193.  actasmpattern: string;
  194.  c: char;
  195.  Instr: TInstruction;
  196.  labellist: TAsmLabelList;
  197.  old_exit : pointer;
  198.  
  199.  
  200.    Procedure SetupTables;
  201.    { creates uppercased symbol tables for speed access }
  202.    var
  203.      i: tasmop;
  204.      j: tregister;
  205.    Begin
  206.      Message(assem_d_creating_lookup_tables);
  207.      { opcodes }
  208.      new(iasmops);
  209.      for i:=firstop to lastop do
  210.       iasmops^[i] := upper(int_op2str[i]);
  211.      { opcodes }
  212.      for j:=firstreg to lastreg do
  213.       iasmregs[j] := upper(int_reg2str[j]);
  214.    end;
  215.  
  216.  
  217.     procedure rai386_exit;{$ifndef FPC}far;{$endif}
  218.  
  219.       begin
  220.          if assigned(iasmops) then
  221.            dispose(iasmops);
  222.          exitproc:=old_exit;
  223.       end;
  224.  
  225.  
  226.   {---------------------------------------------------------------------}
  227.   {                     Routines for the tokenizing                     }
  228.   {---------------------------------------------------------------------}
  229.  
  230.  
  231.    function is_asmopcode(const s: string):Boolean;
  232.   {*********************************************************************}
  233.   { FUNCTION is_asmopcode(s: string):Boolean                            }
  234.   {  Description: Determines if the s string is a valid opcode          }
  235.   {  if so returns TRUE otherwise returns FALSE.                        }
  236.   {*********************************************************************}
  237.    var
  238.     i: tasmop;
  239.     j: byte;
  240.    Begin
  241.      is_asmopcode := FALSE;
  242.      for i:=firstop to lastop do
  243.      begin
  244.        if  s = iasmops^[i] then
  245.        begin
  246.           is_asmopcode:=TRUE;
  247.           exit;
  248.        end;
  249.      end;
  250.      { not found yet, search for extended opcodes }
  251.      for j:=0 to _count_asmspecialops do
  252.      Begin
  253.        if s = _specialops[j] then
  254.        Begin
  255.          is_asmopcode:=TRUE;
  256.          exit;
  257.        end;
  258.      end;
  259.    end;
  260.  
  261.  
  262.  
  263.    Procedure is_asmdirective(const s: string; var token: tinteltoken);
  264.   {*********************************************************************}
  265.   { FUNCTION is_asmdirective(s: string; var token: tinteltoken):Boolean }
  266.   {  Description: Determines if the s string is a valid directive       }
  267.   { (an operator can occur in operand fields, while a directive cannot) }
  268.   {  if so returns the directive token, otherwise does not change token.}
  269.   {*********************************************************************}
  270.    var
  271.     i:byte;
  272.    Begin
  273.      for i:=0 to _count_asmdirectives do
  274.      begin
  275.         if s=_asmdirectives[i] then
  276.         begin
  277.            token := tinteltoken(longint(firstdirective)+i);
  278.            exit;
  279.         end;
  280.      end;
  281.    end;
  282.  
  283.    Procedure is_asmoperator(const s: string; var token: tinteltoken);
  284.   {*********************************************************************}
  285.   { FUNCTION  is_asmoperator(s: string; var token: tinteltoken): Boolean}
  286.   {  Description: Determines if the s string is a valid operator        }
  287.   { (an operator can occur in operand fields, while a directive cannot) }
  288.   {  if so returns the operator token, otherwise does not change token. }
  289.   {*********************************************************************}
  290.    var
  291.     i:longint;
  292.    Begin
  293.      for i:=0 to _count_asmoperators do
  294.      begin
  295.         if s=_asmoperators[i] then
  296.         begin
  297.            token := tinteltoken(longint(firstoperator)+i);
  298.            exit;
  299.         end;
  300.      end;
  301.    end;
  302.  
  303.  
  304.  
  305.  
  306.  
  307.    Procedure is_register(const s: string; var token: tinteltoken);
  308.   {*********************************************************************}
  309.   { PROCEDURE is_register(s: string; var token: tinteltoken);           }
  310.   {  Description: Determines if the s string is a valid register, if    }
  311.   {  so return token equal to A_REGISTER, otherwise does not change token}
  312.   {*********************************************************************}
  313.    Var
  314.     i: tregister;
  315.    Begin
  316.      for i:=firstreg to lastreg do
  317.      begin
  318.       if s=iasmregs[i] then
  319.       begin
  320.         token := AS_REGISTER;
  321.         exit;
  322.       end;
  323.      end;
  324.    end;
  325.  
  326.  
  327.  
  328.  
  329.   Function GetToken: tinteltoken;
  330.   {*********************************************************************}
  331.   { FUNCTION GetToken: tinteltoken;                                     }
  332.   {  Description: This routine returns intel assembler tokens and       }
  333.   {  does some minor syntax error checking.                             }
  334.   {*********************************************************************}
  335.   var
  336.    j: integer;
  337.    token: tinteltoken;
  338.    forcelabel: boolean;
  339.    errorflag : boolean;
  340.   begin
  341.     errorflag := FALSE;
  342.     forcelabel := FALSE;
  343.     actasmpattern :='';
  344.     {* INIT TOKEN TO NOTHING *}
  345.     token := AS_NONE;
  346.     { while space and tab , continue scan... }
  347.     while (c in [' ',#9]) do
  348.       c := asmgetchar;
  349.     { Possiblities for first token in a statement:                }
  350.     {   Local Label, Label, Directive, Prefix or Opcode....       }
  351.     if firsttoken and not (c in [newline,#13,'{',';']) then
  352.     begin
  353.       firsttoken := FALSE;
  354.       if c = '@' then
  355.       begin
  356.         token := AS_LLABEL;   { this is a local label }
  357.         { Let us point to the next character }
  358.         c := asmgetchar;
  359.       end;
  360.  
  361.  
  362.  
  363.       while c in ['A'..'Z','a'..'z','0'..'9','_','@'] do
  364.       begin
  365.          { if there is an at_sign, then this must absolutely be a label }
  366.          if c = '@' then forcelabel:=TRUE;
  367.          actasmpattern := actasmpattern + c;
  368.          c := asmgetchar;
  369.       end;
  370.  
  371.       uppervar(actasmpattern);
  372.  
  373.       if c = ':' then
  374.       begin
  375.            case token of
  376.              AS_NONE: token := AS_LABEL;
  377.              AS_LLABEL: ; { do nothing }
  378.            end; { end case }
  379.            { let us point to the next character }
  380.            c := asmgetchar;
  381.            gettoken := token;
  382.            exit;
  383.       end;
  384.  
  385.       { Are we trying to create an identifier with }
  386.       { an at-sign...?                             }
  387.       if forcelabel then
  388.        Message(assem_e_none_label_contain_at);
  389.  
  390.       If is_asmopcode(actasmpattern) then
  391.       Begin
  392.        gettoken := AS_OPCODE;
  393.        { check if we are in an expression  }
  394.        { then continue with asm directives }
  395.        if not inexpression then
  396.          exit;
  397.       end;
  398.       is_asmdirective(actasmpattern, token);
  399.       if (token <> AS_NONE) then
  400.       Begin
  401.         gettoken := token;
  402.         exit
  403.       end
  404.       else
  405.       begin
  406.          gettoken := AS_NONE;
  407.          Message1(assem_e_invalid_operand,actasmpattern);
  408.       end;
  409.     end
  410.     else { else firsttoken }
  411.     { Here we must handle all possible cases                              }
  412.     begin
  413.       case c of
  414.  
  415.          '@':   { possiblities : - local label reference , such as in jmp @local1 }
  416.                 {                - @Result, @Code or @Data special variables.     }
  417.                             begin
  418.                              actasmpattern := c;
  419.                              c:= asmgetchar;
  420.                              while c in  ['A'..'Z','a'..'z','0'..'9','_','@'] do
  421.                              begin
  422.                                actasmpattern := actasmpattern + c;
  423.                                c := asmgetchar;
  424.                              end;
  425.                              uppervar(actasmpattern);
  426.                              gettoken := AS_ID;
  427.                              exit;
  428.                             end;
  429.       { identifier, register, opcode, prefix or directive }
  430.          'A'..'Z','a'..'z','_': begin
  431.                              actasmpattern := c;
  432.                              c:= asmgetchar;
  433.                              while c in  ['A'..'Z','a'..'z','0'..'9','_'] do
  434.                              begin
  435.                                actasmpattern := actasmpattern + c;
  436.                                c := asmgetchar;
  437.                              end;
  438.                              uppervar(actasmpattern);
  439.  
  440.                              If is_asmopcode(actasmpattern) then
  441.                              Begin
  442.                                     gettoken := AS_OPCODE;
  443.                                     { if we are not in a constant }
  444.                                     { expression than this is an  }
  445.                                     { opcode.                     }
  446.                                     if  not inexpression then
  447.                                     exit;
  448.                              end;
  449.                              is_register(actasmpattern, token);
  450.                              is_asmoperator(actasmpattern,token);
  451.                              is_asmdirective(actasmpattern,token);
  452.                              { if found }
  453.                              if (token <> AS_NONE) then
  454.                              begin
  455.                                gettoken := token;
  456.                                exit;
  457.                              end
  458.                              { this is surely an identifier }
  459.                              else
  460.                                token := AS_ID;
  461.                              gettoken := token;
  462.                              exit;
  463.                           end;
  464.            { override operator... not supported }
  465.            '&':       begin
  466.                          Message(assem_w_override_op_not_supported);
  467.                          c:=asmgetchar;
  468.                          gettoken := AS_NONE;
  469.                       end;
  470.            { string or character }
  471.            '''' :
  472.                       begin
  473.                          actasmpattern:='';
  474.                          while true do
  475.                          begin
  476.                            if c = '''' then
  477.                            begin
  478.                               c:=asmgetchar;
  479.                               if c=newline then
  480.                               begin
  481.                                  Message(scan_f_string_exceeds_line);
  482.                                  break;
  483.                               end;
  484.                               repeat
  485.                                   if c=''''then
  486.                                    begin
  487.                                        c:=asmgetchar;
  488.                                        if c='''' then
  489.                                         begin
  490.                                                actasmpattern:=actasmpattern+'''';
  491.                                                c:=asmgetchar;
  492.                                                if c=newline then
  493.                                                begin
  494.                                                     Message(scan_f_string_exceeds_line);
  495.                                                     break;
  496.                                                end;
  497.                                         end
  498.                                         else break;
  499.                                    end
  500.                                    else
  501.                                    begin
  502.                                           actasmpattern:=actasmpattern+c;
  503.                                           c:=asmgetchar;
  504.                                           if c=newline then
  505.                                             begin
  506.                                                Message(scan_f_string_exceeds_line);
  507.                                                break
  508.                                             end;
  509.                                    end;
  510.                               until false; { end repeat }
  511.                            end
  512.                            else break; { end if }
  513.                          end; { end while }
  514.                    token:=AS_STRING;
  515.                    gettoken := token;
  516.                    exit;
  517.                  end;
  518.            { string or character }
  519.            '"' :
  520.                       begin
  521.                          actasmpattern:='';
  522.                          while true do
  523.                          begin
  524.                            if c = '"' then
  525.                            begin
  526.                               c:=asmgetchar;
  527.                               if c=newline then
  528.                               begin
  529.                                  Message(scan_f_string_exceeds_line);
  530.                                  break;
  531.                               end;
  532.                               repeat
  533.                                   if c='"'then
  534.                                    begin
  535.                                        c:=asmgetchar;
  536.                                        if c='"' then
  537.                                         begin
  538.                                                actasmpattern:=actasmpattern+'"';
  539.                                                c:=asmgetchar;
  540.                                                if c=newline then
  541.                                                begin
  542.                                                   Message(scan_f_string_exceeds_line);
  543.                                                   break;
  544.                                                end;
  545.                                         end
  546.                                        else break;
  547.  
  548.                                    end
  549.                                   else
  550.                                    begin
  551.                                           actasmpattern:=actasmpattern+c;
  552.                                           c:=asmgetchar;
  553.                                           if c=newline then
  554.                                             begin
  555.                                                Message(scan_f_string_exceeds_line);
  556.                                                break
  557.                                             end;
  558.                                    end;
  559.                               until false; { end repeat }
  560.                            end
  561.                            else break; { end if }
  562.                          end; { end while }
  563.                    token := AS_STRING;
  564.                    gettoken := token;
  565.                    exit;
  566.                  end;
  567.            '$' :  begin
  568.                     c:=asmgetchar;
  569.                     while c in ['0'..'9','A'..'F','a'..'f'] do
  570.                     begin
  571.                       actasmpattern := actasmpattern + c;
  572.                       c := asmgetchar;
  573.                     end;
  574.                    gettoken := AS_HEXNUM;
  575.                    exit;
  576.                   end;
  577.            ',' : begin
  578.                    gettoken := AS_COMMA;
  579.                    c:=asmgetchar;
  580.                    exit;
  581.                  end;
  582.            '[' : begin
  583.                    gettoken := AS_LBRACKET;
  584.                    c:=asmgetchar;
  585.                    exit;
  586.                  end;
  587.            ']' : begin
  588.                    gettoken := AS_RBRACKET;
  589.                    c:=asmgetchar;
  590.                    exit;
  591.                  end;
  592.            '(' : begin
  593.                    gettoken := AS_LPAREN;
  594.                    c:=asmgetchar;
  595.                    exit;
  596.                  end;
  597.            ')' : begin
  598.                    gettoken := AS_RPAREN;
  599.                    c:=asmgetchar;
  600.                    exit;
  601.                  end;
  602.            ':' : begin
  603.                    gettoken := AS_COLON;
  604.                    c:=asmgetchar;
  605.                    exit;
  606.                  end;
  607.            '.' : begin
  608.                    gettoken := AS_DOT;
  609.                    c:=asmgetchar;
  610.                    exit;
  611.                  end;
  612.            '+' : begin
  613.                    gettoken := AS_PLUS;
  614.                    c:=asmgetchar;
  615.                    exit;
  616.                  end;
  617.            '-' : begin
  618.                    gettoken := AS_MINUS;
  619.                    c:=asmgetchar;
  620.                    exit;
  621.                  end;
  622.            '*' : begin
  623.                    gettoken := AS_STAR;
  624.                    c:=asmgetchar;
  625.                    exit;
  626.                  end;
  627.            '/' : begin
  628.                    gettoken := AS_SLASH;
  629.                    c:=asmgetchar;
  630.                    exit;
  631.                  end;
  632.            '0'..'9': begin
  633.                           { this flag indicates if there was an error  }
  634.                           { if so, then we use a default value instead.}
  635.                           errorflag := false;
  636.                           actasmpattern := c;
  637.                           c := asmgetchar;
  638.                           { Get the possible characters }
  639.                           while c in ['0'..'9','A'..'F','a'..'f'] do
  640.                           begin
  641.                             actasmpattern := actasmpattern + c;
  642.                             c:= asmgetchar;
  643.                           end;
  644.                           { Get ending character }
  645.                           uppervar(actasmpattern);
  646.                           c:=upcase(c);
  647.                           { possibly a binary number. }
  648.                           if (actasmpattern[length(actasmpattern)] = 'B') and (c <> 'H') then
  649.                           Begin
  650.                                   { Delete the last binary specifier }
  651.                                   delete(actasmpattern,length(actasmpattern),1);
  652.                                   for j:=1 to length(actasmpattern) do
  653.                                    if not (actasmpattern[j] in ['0','1']) then
  654.                                    begin
  655.                                        Message1(assem_e_error_in_binary_const,actasmpattern);
  656.                                        errorflag := TRUE;
  657.                                    end;
  658.                                  { if error, then suppose a binary value of zero. }
  659.                                  if errorflag then
  660.                                    actasmpattern := '0';
  661.                                  gettoken := AS_BINNUM;
  662.                                  exit;
  663.                           end
  664.                           else
  665.                           Begin
  666.                              case c of
  667.                               'O': Begin
  668.                                       for j:=1 to length(actasmpattern) do
  669.                                         if not (actasmpattern[j] in ['0'..'7']) then
  670.                                         begin
  671.                                           Message1(assem_e_error_in_octal_const,actasmpattern);
  672.                                           errorflag := TRUE;
  673.                                         end;
  674.                                  { if error, then suppose an octal value of zero. }
  675.                                      if errorflag then
  676.                                         actasmpattern := '0';
  677.                                       gettoken := AS_OCTALNUM;
  678.                                       c := asmgetchar;
  679.                                       exit;
  680.                                     end;
  681.                               'H': Begin
  682.                                       for j:=1 to length(actasmpattern) do
  683.                                         if not (actasmpattern[j] in ['0'..'9','A'..'F']) then
  684.                                         begin
  685.                                           Message1(assem_e_error_in_hex_const,actasmpattern);
  686.                                           errorflag := TRUE;
  687.                                         end;
  688.                                  { if error, then suppose an hex value of zero. }
  689.                                      if errorflag then
  690.                                         actasmpattern := '0';
  691.                                      gettoken := AS_HEXNUM;
  692.                                      c := asmgetchar;
  693.                                      exit;
  694.                                    end;
  695.                               else { must be an integer number }
  696.                                begin
  697.                                     for j:=1 to length(actasmpattern) do
  698.                                      if not (actasmpattern[j] in ['0'..'9']) then
  699.                                      begin
  700.                                          Message1(assem_e_error_in_integer_const,actasmpattern);
  701.                                          errorflag := TRUE;
  702.                                      end;
  703.                                  { if error, then suppose an int value of zero. }
  704.                                      if errorflag then
  705.                                         actasmpattern := '0';
  706.                                      gettoken := AS_INTNUM;
  707.                                      exit;
  708.                               end;
  709.                           end; { end case }
  710.                       end; { end if }
  711.                      end;
  712.     ';','{',#13,newline : begin
  713.                             c:=asmgetchar;
  714.                             firsttoken := TRUE;
  715.                             gettoken:=AS_SEPARATOR;
  716.                            end;
  717.             else
  718.              Begin
  719.                Message(scan_f_illegal_char);
  720.              end;
  721.  
  722.       end; { end case }
  723.     end; { end else if }
  724.   end;
  725.  
  726.   {---------------------------------------------------------------------}
  727.   {                     Routines for the output                         }
  728.   {---------------------------------------------------------------------}
  729.  
  730.    { returns an appropriate ao_xxxx flag indicating the type }
  731.    { of operand.                                             }
  732.    function findtype(Var Opr: TOperand): longint;
  733.    Begin
  734.     With Opr do
  735.     Begin
  736.      case operandtype of
  737.        OPR_REFERENCE:   Begin
  738.                            if assigned(ref.symbol) then
  739.                            { check if in local label list }
  740.                            { if so then it is considered  }
  741.                            { as a displacement.           }
  742.                            Begin
  743.                              if labellist.search(ref.symbol^) <> nil then
  744.                                findtype := ao_disp
  745.                              else
  746.                                findtype := ao_mem; { probably a mem ref. }
  747.                            end
  748.                            else
  749.                             findtype := ao_mem;
  750.                         end;
  751.        OPR_CONSTANT: Begin
  752.                        { check if there is not already a default size }
  753.                        if opr.size <> S_NO then
  754.                        Begin
  755.                           findtype := _constsizes[opr.size];
  756.                          exit;
  757.                        end;
  758.                        if val < $ff then
  759.                        Begin
  760.                          findtype := ao_imm8;
  761.                          opr.size := S_B;
  762.                        end
  763.                        else if val < $ffff then
  764.                        Begin
  765.                          findtype := ao_imm16;
  766.                          opr.size := S_W;
  767.                        end
  768.                        else
  769.                        Begin
  770.                          findtype := ao_imm32;
  771.                          opr.size := S_L;
  772.                        end
  773.                      end;
  774.        OPR_REGISTER: Begin
  775.                       findtype := _regtypes[reg];
  776.                       exit;
  777.                      end;
  778.        OPR_NONE:     Begin
  779.                        findtype := 0;
  780.                      end;
  781.        else
  782.        Begin
  783.          Message(assem_f_internal_error_in_findtype);
  784.        end;
  785.      end;
  786.     end;
  787.    end;
  788.  
  789.  
  790.  
  791.     Procedure ConcatLabeledInstr(var instr: TInstruction);
  792.     Begin
  793.        if (instr.getinstruction in [A_JO,A_JNO,A_JB,A_JC,A_JNAE,
  794.         A_JNB,A_JNC,A_JAE,A_JE,A_JZ,A_JNE,A_JNZ,A_JBE,A_JNA,A_JNBE,
  795.         A_JA,A_JS,A_JNS,A_JP,A_JPE,A_JNP,A_JPO,A_JL,A_JNGE,A_JNL,A_JGE,
  796.         A_JLE,A_JNG,A_JNLE,A_JG,A_JCXZ,A_JECXZ,A_LOOP,A_LOOPZ,A_LOOPE,
  797.         A_LOOPNZ,A_LOOPNE,A_MOV,A_JMP,A_CALL]) then
  798.        Begin
  799.         if instr.numops > 1 then
  800.          Message(assem_e_invalid_labeled_opcode)
  801.         else if instr.operands[1].operandtype <> OPR_LABINSTR then
  802.           Message(assem_e_invalid_labeled_opcode)
  803.         else if (instr.operands[1].operandtype = OPR_LABINSTR) and
  804.          (instr.numops = 1) then
  805.            if assigned(instr.operands[1].hl) then
  806.             ConcatLabel(p,instr.getinstruction, instr.operands[1].hl)
  807.            else
  808.             Message(assem_f_internal_error_in_findtype);
  809.        end
  810.        else if instr.getinstruction = A_MOV then
  811.        Begin
  812.          { MOV to rel8 }
  813.        end
  814.        else
  815.         Message(assem_e_invalid_operand);
  816.     end;
  817.  
  818.  
  819.  
  820.  
  821.    Procedure HandleExtend(var instr: TInstruction);
  822.    { Handles MOVZX, MOVSX ... }
  823.    var
  824.      instruc: tasmop;
  825.      opsize: topsize;
  826.    Begin
  827.       instruc:=instr.getinstruction;
  828.       { return the old types ..}
  829.       { these tokens still point to valid intel strings, }
  830.       { but we must convert them to TRUE intel tokens    }
  831.       if instruc in [A_MOVSB,A_MOVSBL,A_MOVSBW,A_MOVSWL] then
  832.         instruc := A_MOVSX;
  833.       if instruc in [A_MOVZB,A_MOVZWL] then
  834.         instruc := A_MOVZX;
  835.  
  836.      With instr do
  837.  
  838.          Begin
  839.            if operands[1].size = S_B then
  840.            Begin
  841.               if operands[2].size = S_L then
  842.                  opsize := S_BL
  843.               else
  844.               if operands[2].size = S_W then
  845.                  opsize := S_BW
  846.               else
  847.               begin
  848.                  Message(assem_e_invalid_size_movzx);
  849.                  exit;
  850.               end;
  851.  
  852.            end
  853.            else
  854.            if operands[1].size = S_W then
  855.            Begin
  856.              if operands[2].size = S_L then
  857.                 opsize := S_WL
  858.              else
  859.              begin
  860.                  Message(assem_e_invalid_size_movzx);
  861.                  exit;
  862.              end;
  863.            end
  864.            else
  865.            begin
  866.                  Message(assem_e_invalid_size_movzx);
  867.                  exit;
  868.            end;
  869.  
  870.  
  871.            if operands[1].operandtype = OPR_REGISTER then
  872.            Begin
  873.               if operands[2].operandtype <> OPR_REGISTER then
  874.                Message(assem_e_invalid_opcode)
  875.               else
  876.                  p^.concat(new(pai386,op_reg_reg(instruc,opsize,
  877.                    operands[1].reg,operands[2].reg)));
  878.            end
  879.            else
  880.            if operands[1].operandtype = OPR_REFERENCE then
  881.            Begin
  882.               if operands[2].operandtype <> OPR_REGISTER then
  883.                Message(assem_e_invalid_opcode)
  884.               else
  885.                  p^.concat(new(pai386,op_ref_reg(instruc,opsize,
  886.                    newreference(operands[1].ref),operands[2].reg)));
  887.            end
  888.      end; { end with }
  889.    end;
  890.  
  891.  
  892.   Procedure ConcatOpCode(var instr: TInstruction);
  893.   {*********************************************************************}
  894.   { First Pass:                                                         }
  895.   {       if instr = Lxxx with a 16bit offset, we emit an error.        }
  896.   {       If the instruction is INS,IN,OUT,OUTS,RCL,ROL,RCR,ROR,        }
  897.   {        SAL,SAR,SHL,SHR,SHLD,SHRD,DIV,IDIV,BT,BTC,BTR,BTS,INT,       }
  898.   {        RET,ENTER,SCAS,CMPS,STOS,LODS,FNSTSW,FSTSW.                  }
  899.   {         set up the optypes variables manually, as well as setting   }
  900.   {         operand sizes.                                              }
  901.   { Second pass:                                                        }
  902.   {  Check if the combination of opcodes and operands are valid, using  }
  903.   {  the opcode table.                                                  }
  904.   { Third pass:                                                         }
  905.   {    If there was no error on the 2nd pass  , then we check the       }
  906.   {    following:                                                       }
  907.   {    - If this is a 0 operand opcode                                  }
  908.   {        we verify if it is a string opcode, if so we emit a size also}
  909.   {        otherwise simply emit the opcode by itself.                  }
  910.   {    - If this is a 1 operand opcode, and it is a reference, we make  }
  911.   {      sure that the operand size is valid; we emit the opcode.       }
  912.   {    - If this is a two operand opcode                                }
  913.   {      o if the opcode is MOVSX or MOVZX then we handle it specially  }
  914.   {      o we check the operand types (most important combinations):    }
  915.   {            if reg,reg we make sure that both registers are of the   }
  916.   {             same size.                                              }
  917.   {            if reg,ref or ref,reg we check if the symbol name is     }
  918.   {             assigned, if so a size must be specified and compared   }
  919.   {             to the register size, both must be equal. If there is   }
  920.   {             no symbol name, then we check :                         }
  921.   {                if refsize = NO_SIZE then OPCODE_SIZE = regsize      }
  922.   {                  else if refsize = regsize then OPCODE_SIZE = regsize}
  923.   {                   else error.                                       }
  924.   {                   if no_error emit the opcode.                      }
  925.   {            if ref,const or const,ref if ref does not have any size  }
  926.   {              then error, otherwise emit the opcode.                 }
  927.   {    - If this is a three operand opcode:                             }
  928.   {          imul,shld,and shrd  -> check them manually.                }
  929.   {*********************************************************************}
  930.   var
  931.     fits : boolean;
  932.     i: longint;
  933.     opsize: topsize;
  934.     optyp1, optyp2, optyp3: longint;
  935.     instruc: tasmop;
  936.   Begin
  937.      fits := FALSE;
  938.      for i:=1 to instr.numops do
  939.      Begin
  940.        case instr.operands[i].operandtype of
  941.          OPR_REGISTER: instr.operands[i].size :=
  942.                          _regsizes[instr.operands[i].reg];
  943.        end; { end case }
  944.      end; { endif }
  945.     { setup specific instructions for first pass }
  946.     instruc := instr.getinstruction;
  947.     if (instruc in [A_LEA,A_LDS,A_LSS,A_LES,A_LFS,A_LGS]) then
  948.     Begin
  949.        if instr.operands[1].size <> S_L then
  950.        Begin
  951.          Message(assem_e_16bit_base_in_32bit_segment);
  952.          exit;
  953.        end; { endif }
  954.     end;
  955.  
  956.     With instr do
  957.     Begin
  958.  
  959.  
  960.       for i:=1 to numops do
  961.       Begin
  962.          With operands[i] do
  963.          Begin
  964.          { check for 16-bit bases/indexes and emit an error.   }
  965.          { we cannot only emit a warning since gas does not    }
  966.          { accept 16-bit indexes and bases.                    }
  967.           if (operandtype = OPR_REFERENCE) and
  968.             ((ref.base <> R_NO) or
  969.             (ref.index <> R_NO)) then
  970.             Begin
  971.             { index or base defined. }
  972.               if (ref.base <> R_NO) then
  973.               Begin
  974.                 if not (ref.base in
  975.                   [R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESI,R_EDI,R_ESP]) then
  976.                     Message(assem_e_16bit_base_in_32bit_segment);
  977.               end;
  978.             { index or base defined. }
  979.               if (ref.index <> R_NO) then
  980.               Begin
  981.                   if not (ref.index in
  982.                     [R_EAX,R_EBX,R_ECX,R_EDX,R_EBP,R_ESI,R_EDI,R_ESP]) then
  983.                     Message(assem_e_16bit_index_in_32bit_segment);
  984.               end;
  985.             end;
  986.             { Check for constants without bases/indexes in memory }
  987.             { references.                                         }
  988.             if (operandtype = OPR_REFERENCE) and
  989.                (ref.base = R_NO) and
  990.                (ref.index = R_NO) and
  991.                (ref.symbol = nil) and
  992.                (ref.offset <> 0) then
  993.                Begin
  994.                  ref.isintvalue := TRUE;
  995.                  Message(assem_e_const_ref_not_allowed);
  996.                end;
  997.  
  998.               opinfo := findtype(operands[i]);
  999.  
  1000.           end; { end with }
  1001.       end; {endfor}
  1002.  
  1003.  
  1004.  
  1005.  
  1006.        { TAKE CARE OF SPECIAL OPCODES, TAKE CARE OF THEM INDIVUALLY.    }
  1007.        { ALL THE REST ARE TAKEN CARE BY OPCODE TABLE AND THIRD PASS.    }
  1008.        if instruc = A_FST then
  1009.        Begin
  1010.        end
  1011.        else
  1012.        if instruc = A_FILD then
  1013.        Begin
  1014.        end
  1015.        else
  1016.        if instruc = A_FLD then
  1017.        Begin
  1018.             {A_FLDS,A_FLDL,A_FLDT}
  1019.        end
  1020.        else
  1021.        if instruc = A_FIST then
  1022.        Begin
  1023.             {A_FISTQ,A_FISTS,A_FISTL}
  1024.        end
  1025.        else
  1026.        if instruc = A_FWAIT then
  1027.         FWaitWarning
  1028.        else
  1029.        if instruc = A_MOVSX then
  1030.        Begin
  1031.          { change the instruction to conform to GAS }
  1032.          if operands[1].size = S_W then
  1033.          Begin
  1034.              addinstr(A_MOVSBW)
  1035.          end
  1036.          else
  1037.          if operands[1].size = S_L then
  1038.          Begin
  1039.              if operands[2].size = S_B then
  1040.                 addinstr(A_MOVSBL)
  1041.              else
  1042.                 addinstr(A_MOVSWL);
  1043.          end;
  1044.          instruc := getinstruction; { reload instruction }
  1045.        end
  1046.        else
  1047.        if instruc = A_MOVZX then
  1048.        Begin
  1049.          { change the instruction to conform to GAS }
  1050.          if operands[1].size = S_W then
  1051.          Begin
  1052.              addinstr(A_MOVZB)
  1053.          end
  1054.          else
  1055.          if operands[1].size = S_L then
  1056.          Begin
  1057.              if operands[2].size = S_B then
  1058.                 addinstr(A_MOVZB)
  1059.              else
  1060.                 addinstr(A_MOVZWL);
  1061.          end;
  1062.          instruc := getinstruction; { reload instruction }
  1063.        end
  1064.        else
  1065.        if (instruc in [A_BT,A_BTC,A_BTR,A_BTS]) then
  1066.        Begin
  1067.           if numops = 2 then
  1068.             Begin
  1069.                 if (operands[2].operandtype = OPR_CONSTANT)
  1070.                 and (operands[2].val <= $ff) then
  1071.                   Begin
  1072.                      operands[2].opinfo := ao_imm8;
  1073.                      { no operand size if using constant. }
  1074.                      operands[2].size := S_NO;
  1075.                      fits := TRUE;
  1076.                   end
  1077.             end
  1078.           else
  1079.             Begin
  1080.                 Message(assem_e_invalid_opcode_and_operand);
  1081.                 exit;
  1082.             end;
  1083.        end
  1084.        else
  1085.        if instruc = A_ENTER then
  1086.        Begin
  1087.           if numops =2 then
  1088.             Begin
  1089.                if (operands[1].operandtype = OPR_CONSTANT) and
  1090.                   (operands[1].val <= $ffff) then
  1091.                   Begin
  1092.                      operands[1].opinfo := ao_imm16;
  1093.                   end  { endif }
  1094.             end { endif }
  1095.           else
  1096.             Begin
  1097.                 Message(assem_e_invalid_opcode_and_operand);
  1098.                 exit;
  1099.             end
  1100.        end { endif }
  1101.        else
  1102.      {  Handle special opcodes for the opcode   }
  1103.      {  table. Set them up correctly.           }
  1104.        if (instruc in [A_IN,A_INS]) then
  1105.        Begin
  1106.           if numops =2 then
  1107.             Begin
  1108.               if (operands[2].operandtype = OPR_REGISTER) and (operands[2].reg = R_DX)
  1109.                then
  1110.                Begin
  1111.                   operands[2].opinfo := ao_inoutportreg;
  1112.                   if (operands[1].operandtype = OPR_REGISTER) and
  1113.                     (operands[1].reg in [R_EAX,R_AX,R_AL]) and
  1114.                     (instruc = A_IN) then
  1115.                     Begin
  1116.                        operands[1].opinfo := ao_acc;
  1117.                     end
  1118.                end
  1119.               else
  1120.               if (operands[2].operandtype = OPR_CONSTANT) and (operands[2].val <= $ff)
  1121.                 and (instruc = A_IN) then
  1122.                 Begin
  1123.                   operands[2].opinfo := ao_imm8;
  1124.                   operands[2].size := S_B;
  1125.                  if (operands[1].operandtype = OPR_REGISTER) and
  1126.                     (operands[1].reg in [R_EAX,R_AX,R_AL]) and
  1127.                     (instruc = A_IN) then
  1128.                     Begin
  1129.                        operands[1].opinfo := ao_acc;
  1130.                     end
  1131.                 end;
  1132.             end
  1133.           else
  1134.             if not ((numops=0) and (instruc=A_INS)) then
  1135.              Begin
  1136.                Message(assem_e_invalid_opcode_and_operand);
  1137.                exit;
  1138.              end;
  1139.        end
  1140.        else
  1141.        if (instruc in [A_OUT,A_OUTS]) then
  1142.        Begin
  1143.           if numops =2 then
  1144.             Begin
  1145.               if (operands[1].operandtype = OPR_REGISTER) and (operands[1].reg = R_DX)
  1146.                then
  1147.                Begin
  1148.                   operands[1].opinfo := ao_inoutportreg;
  1149.                   if (operands[2].operandtype = OPR_REGISTER) and
  1150.                      (operands[2].reg in [R_EAX,R_AX,R_AL]) and
  1151.                      (instruc = A_OUT) then
  1152.                      Begin
  1153.                        operands[2].opinfo := ao_acc;
  1154.                        fits := TRUE;
  1155.                      end
  1156.                end
  1157.               else
  1158.               if (operands[1].operandtype = OPR_CONSTANT) and (operands[1].val <= $ff)
  1159.                 and (instruc = A_OUT) then
  1160.                 Begin
  1161.                   operands[1].opinfo := ao_imm8;
  1162.                   operands[1].size := S_B;
  1163.                   if (operands[2].operandtype = OPR_REGISTER) and
  1164.                      (operands[2].reg in [R_EAX,R_AX,R_AL]) and
  1165.                      (instruc = A_OUT) then
  1166.                      Begin
  1167.                        operands[2].opinfo := ao_acc;
  1168.                        fits := TRUE;
  1169.                      end
  1170.                 end;
  1171.             end
  1172.           else
  1173.             if not ((numops=0) and (instruc=A_OUTS)) then
  1174.              Begin
  1175.                Message(assem_e_invalid_opcode_and_operand);
  1176.                exit;
  1177.              end;
  1178.        end
  1179.        else
  1180.        if instruc in [A_RCL,A_RCR,A_ROL,A_ROR,A_SAL,A_SAR,A_SHL,A_SHR] then
  1181.        { if RCL,ROL,... }
  1182.        Begin
  1183.           if numops =2 then
  1184.             Begin
  1185.               if (operands[2].operandtype = OPR_REGISTER) and (operands[2].reg = R_CL)
  1186.               then
  1187.               Begin
  1188.                 operands[2].opinfo := ao_shiftcount
  1189.               end
  1190.               else
  1191.               if (operands[2].operandtype = OPR_CONSTANT) and
  1192.                 (operands[2].val <= $ff) then
  1193.                 Begin
  1194.                    operands[2].opinfo := ao_imm8;
  1195.                    operands[2].size := S_B;
  1196.                 end;
  1197.             end
  1198.           else { if numops = 2 }
  1199.             Begin
  1200.                 Message(assem_e_invalid_opcode_and_operand);
  1201.                 exit;
  1202.             end;
  1203.        end
  1204.        { endif ROL,RCL ... }
  1205.        else
  1206.        if instruc in [A_DIV, A_IDIV] then
  1207.        Begin
  1208.           if (operands[1].operandtype = OPR_REGISTER) and
  1209.             (operands[1].reg in [R_AL,R_AX,R_EAX]) then
  1210.                 operands[1].opinfo := ao_acc;
  1211.        end
  1212.        else
  1213.        if (instruc = A_FNSTSW) or (instruc = A_FSTSW) then
  1214.        Begin
  1215.           if numops = 1 then
  1216.             Begin
  1217.                 if (operands[1].operandtype = OPR_REGISTER) and
  1218.                   (operands[1].reg = R_AX) then
  1219.                  operands[1].opinfo := ao_acc;
  1220.             end
  1221.           else
  1222.             Begin
  1223.               Message(assem_e_invalid_opcode_and_operand);
  1224.               exit;
  1225.             end;
  1226.        end
  1227.        else
  1228.        if (instruc = A_SHLD) or (instruc = A_SHRD) then
  1229.        { these instruction are fully parsed individually on pass three }
  1230.        { so we just do a summary checking here.                        }
  1231.        Begin
  1232.           if numops = 3 then
  1233.             Begin
  1234.                 if (operands[3].operandtype = OPR_CONSTANT)
  1235.                 and (operands[3].val <= $ff) then
  1236.                 Begin
  1237.                    operands[3].opinfo := ao_imm8;
  1238.                    operands[3].size := S_B;
  1239.                 end;
  1240.             end
  1241.           else
  1242.             Begin
  1243.                 Message(assem_e_invalid_opcode_and_operand);
  1244.                 exit;
  1245.             end;
  1246.        end
  1247.        else
  1248.        if instruc = A_INT then
  1249.        Begin
  1250.           if numops = 1 then
  1251.             Begin
  1252.                if (operands[1].operandtype = OPR_CONSTANT) and
  1253.                  (operands[1].val <= $ff) then
  1254.                       operands[1].opinfo := ao_imm8;
  1255.             end
  1256.        end
  1257.        else
  1258.        if instruc = A_RET then
  1259.        Begin
  1260.           if numops =1 then
  1261.             Begin
  1262.                if (operands[1].operandtype = OPR_CONSTANT) and
  1263.                   (operands[1].val <= $ffff) then
  1264.                     operands[1].opinfo := ao_imm16;
  1265.             end
  1266.        end; { endif }
  1267.  
  1268.        { all string instructions have default memory }
  1269.        { location which are ignored. Take care of    }
  1270.        { those.                                      }
  1271.        { Here could be added the code for segment    }
  1272.        { overrides.                                  }
  1273.        if instruc in [A_SCAS,A_CMPS,A_STOS,A_LODS] then
  1274.        Begin
  1275.           if numops =1 then
  1276.             Begin
  1277.                if (operands[1].operandtype = OPR_REFERENCE) and
  1278.                  (assigned(operands[1].ref.symbol)) then
  1279.                  Freemem(operands[1].ref.symbol,length(operands[1].ref.symbol^)+1);
  1280.                operands[1].operandtype := OPR_NONE;
  1281.                numops := 0;
  1282.             end;
  1283.        end; { endif }
  1284.        if instruc in [A_INS,A_MOVS,A_OUTS] then
  1285.        Begin
  1286.           if numops =2 then
  1287.             Begin
  1288.                if (operands[1].operandtype = OPR_REFERENCE) and
  1289.                  (assigned(operands[1].ref.symbol)) then
  1290.                  Freemem(operands[1].ref.symbol,length(operands[1].ref.symbol^)+1);
  1291.                if (operands[2].operandtype = OPR_REFERENCE) and
  1292.                  (assigned(operands[2].ref.symbol)) then
  1293.                  Freemem(operands[2].ref.symbol,length(operands[1].ref.symbol^)+1);
  1294.                operands[1].operandtype := OPR_NONE;
  1295.                operands[2].operandtype := OPR_NONE;
  1296.                numops := 0;
  1297.             end;
  1298.        end;
  1299.      { handle parameter for segment overrides }
  1300.      if instruc = A_XLAT then
  1301.      Begin
  1302.         { handle special TP syntax case for XLAT }
  1303.         { here we accept XLAT, XLATB and XLAT m8 }
  1304.         if (numops = 1) or (numops = 0) then
  1305.          Begin
  1306.                if (operands[1].operandtype = OPR_REFERENCE) and
  1307.                  (assigned(operands[1].ref.symbol)) then
  1308.                  Freemem(operands[1].ref.symbol,length(operands[1].ref.symbol^)+1);
  1309.                operands[1].operandtype := OPR_NONE;
  1310.                numops := 0;
  1311.                { always a byte for XLAT }
  1312.                instr.stropsize := S_B;
  1313.          end;
  1314.      end;
  1315.  
  1316.  
  1317.  
  1318.     { swap the destination and source }
  1319.     { to put in AT&T style direction  }
  1320.     { only if there are 2/3 operand   }
  1321.     { numbers.                        }
  1322.     if (instruc <> A_ENTER) then
  1323.        SwapOperands(instr);
  1324.     { copy them to local variables }
  1325.     { for faster access            }
  1326.     optyp1:=operands[1].opinfo;
  1327.     optyp2:=operands[2].opinfo;
  1328.     optyp3:=operands[3].opinfo;
  1329.  
  1330.     end; { end with }
  1331.  
  1332.     { after reading the operands }
  1333.     { search the instruction     }
  1334.     { setup startvalue from cache }
  1335.     if ins_cache[instruc]<>-1 then
  1336.        i:=ins_cache[instruc]
  1337.     else i:=0;
  1338.  
  1339.  
  1340.     { this makes cpu.pp uncompilable, but i think this code should be }
  1341.     { inserted in the system unit anyways.                            }
  1342.     if (instruc >= lastop_in_table) and
  1343.        ((cs_compilesystem in aktswitches) or (opt_processors > globals.i386)) then
  1344.       begin
  1345.          Message(assem_w_opcode_not_in_table);
  1346.          fits:=true;
  1347.       end
  1348.     else while not(fits) do
  1349.       begin
  1350.        { set the instruction cache, if the instruction }
  1351.        { occurs the first time                         }
  1352.        if (it[i].i=instruc) and (ins_cache[instruc]=-1) then
  1353.            ins_cache[instruc]:=i;
  1354.  
  1355.        if (it[i].i=instruc) and (instr.numops=it[i].ops) then
  1356.        begin
  1357.           { first fit }
  1358.           case instr.numops of
  1359.           0 : begin
  1360.                  fits:=true;
  1361.                  break;
  1362.               end;
  1363.           1 :
  1364.               Begin
  1365.                 if (optyp1 and it[i].o1)<>0 then
  1366.                 Begin
  1367.                    fits:=true;
  1368.                    break;
  1369.                 end;
  1370.                 { I consider sign-extended 8bit value to }
  1371.                 { be equal to immediate 8bit therefore   }
  1372.                 { convert...                             }
  1373.                 if (optyp1 = ao_imm8) then
  1374.                 Begin
  1375.                   { check if this is a simple sign extend. }
  1376.                   if (it[i].o1<>ao_imm8s) then
  1377.                   Begin
  1378.                     fits:=true;
  1379.                     break;
  1380.                   end;
  1381.                 end;
  1382.               end;
  1383.           2 : if ((optyp1 and it[i].o1)<>0) and
  1384.                ((optyp2 and it[i].o2)<>0) then
  1385.                Begin
  1386.                      fits:=true;
  1387.                      break;
  1388.                end
  1389.                { if the operands can be swaped }
  1390.                { then swap them                }
  1391.                else if ((it[i].m and af_d)<>0) and
  1392.                ((optyp1 and it[i].o2)<>0) and
  1393.                ((optyp2 and it[i].o1)<>0) then
  1394.                begin
  1395.                  { swap the destination and source }
  1396.                  { to put in AT&T style direction  }
  1397. { What does this mean !!!! ???????????????????????? }
  1398. {                 if (output_format in [of_o,of_att]) then }
  1399.                  { ???????????? }
  1400. {                          SwapOperands(instr); }
  1401.                  fits:=true;
  1402.                  break;
  1403.                end;
  1404.           3 : if ((optyp1 and it[i].o1)<>0) and
  1405.                ((optyp2 and it[i].o2)<>0) and
  1406.                ((optyp3 and it[i].o3)<>0) then
  1407.                Begin
  1408.                  fits:=true;
  1409.                  break;
  1410.                end;
  1411.           end; { end case }
  1412.        end; { endif }
  1413.        if it[i].i=A_NONE then
  1414.        begin
  1415.          { NO MATCH! }
  1416.          Message(assem_e_invalid_opcode_and_operand);
  1417.          exit;
  1418.        end;
  1419.        inc(i);
  1420.       end; { end while }
  1421.  
  1422.   { We add the opcode to the opcode linked list }
  1423.   if fits then
  1424.   Begin
  1425.     if instr.getprefix <> A_NONE then
  1426.     Begin
  1427.       p^.concat(new(pai386,op_none(instr.getprefix,S_NO)));
  1428.     end;
  1429.     case instr.numops of
  1430.      0:
  1431.         if instr.stropsize <> S_NO then
  1432.         { is this a string operation opcode or xlat then check }
  1433.         { the size of the operation.                           }
  1434.           p^.concat(new(pai386,op_none(instruc,instr.stropsize)))
  1435.         else
  1436.           p^.concat(new(pai386,op_none(instruc,S_NO)));
  1437.      1: Begin
  1438.           case instr.operands[1].operandtype of
  1439.                { all one operand opcodes with constant have no defined sizes }
  1440.                { at least that is what it seems in the tasm 2.0 manual.      }
  1441.            OPR_CONSTANT:  p^.concat(new(pai386,op_const(instruc,
  1442.                              S_NO, instr.operands[1].val)));
  1443.                { the size of the operand can be determined by the as,nasm and }
  1444.                { tasm.                                                        }
  1445.                { Even though normally gas should not be trusted, v2.8.1       }
  1446.                { has been *extensively* tested to assure that the output      }
  1447.                { is indeed correct with the following opcodes: push and pop   }
  1448.            OPR_REGISTER: if instruc in [A_INC,A_DEC, A_NEG,A_NOT] then
  1449.                          Begin
  1450.                            p^.concat(new(pai386,op_reg(instruc,
  1451.                                instr.operands[1].size,instr.operands[1].reg)));
  1452.                          end
  1453.                          else
  1454.                            p^.concat(new(pai386,op_reg(instruc,
  1455.                                S_NO,instr.operands[1].reg)));
  1456.                { this is where it gets a bit more complicated...              }
  1457.            OPR_REFERENCE:
  1458.                           if instr.operands[1].size <> S_NO then
  1459.                           Begin
  1460.                            p^.concat(new(pai386,op_ref(instruc,
  1461.                             instr.operands[1].size,newreference(instr.operands[1].ref))));
  1462.                           end
  1463.                           else
  1464.                           Begin
  1465.                               { special jmp and call case with }
  1466.                               { symbolic references.           }
  1467.                               if instruc in [A_CALL,A_JMP] then
  1468.                               Begin
  1469.                                 p^.concat(new(pai386,op_ref(instruc,
  1470.                                   S_NO,newreference(instr.operands[1].ref))));
  1471.                               end
  1472.                               else
  1473.                                 Message(assem_e_invalid_opcode_and_operand);
  1474.                           end;
  1475.            OPR_NONE: Begin
  1476.                        Message(assem_f_internal_error_in_concatopcode);
  1477.                      end;
  1478.           else
  1479.            Begin
  1480.             Message(assem_f_internal_error_in_concatopcode);
  1481.            end;
  1482.           end;
  1483.         end;
  1484.      2:
  1485.         Begin
  1486.            if instruc in [A_MOVSX,A_MOVZX,A_MOVSB,A_MOVSBL,A_MOVSBW,
  1487.              A_MOVSWL,A_MOVZB,A_MOVZWL] then
  1488.               { movzx and movsx }
  1489.               HandleExtend(instr)
  1490.            else
  1491.              { other instructions }
  1492.              Begin
  1493.                 With instr do
  1494.                 Begin
  1495.                 { source }
  1496.                   opsize := operands[1].size;
  1497.                   case operands[1].operandtype of
  1498.                   { reg,reg     }
  1499.                   { reg,ref     }
  1500.                    OPR_REGISTER:
  1501.                      Begin
  1502.                        case operands[2].operandtype of
  1503.                          OPR_REGISTER:
  1504.                             { see info in ratti386.pas, about the problem }
  1505.                             { which can cause gas here.                   }
  1506.                             if (opsize = operands[2].size) then
  1507.                             begin
  1508.                                p^.concat(new(pai386,op_reg_reg(instruc,
  1509.                                opsize,operands[1].reg,operands[2].reg)));
  1510.                             end
  1511.                             else
  1512.                             { these do not require any size specification. }
  1513.                             if (instruc in [A_IN,A_OUT,A_SAL,A_SAR,A_SHL,A_SHR,A_ROL,
  1514.                                A_ROR,A_RCR,A_RCL])  then
  1515.                                { outs and ins are already taken care by }
  1516.                                { the first pass.                        }
  1517.                                p^.concat(new(pai386,op_reg_reg(instruc,
  1518.                                S_NO,operands[1].reg,operands[2].reg)))
  1519.                             else
  1520.                             Begin
  1521.                               Message(assem_e_invalid_opcode_and_operand);
  1522.                             end;
  1523.                          OPR_REFERENCE:
  1524.                            { variable name. }
  1525.                            { here we must check the instruction type }
  1526.                            { before deciding if to use and compare   }
  1527.                            { any sizes.                              }
  1528.                            if assigned(operands[2].ref.symbol) then
  1529.                            Begin
  1530.                               if (opsize = operands[2].size) or (instruc in
  1531.                                [A_RCL,A_RCR,A_ROL,A_ROR,A_SAL,A_SAR,A_SHR,A_SHL]) then
  1532.                                   p^.concat(new(pai386,op_reg_ref(instruc,
  1533.                                   opsize,operands[1].reg,newreference(operands[2].ref))))
  1534.                               else
  1535.                                   Message(assem_e_invalid_size_in_ref);
  1536.                            end
  1537.                            else
  1538.                            Begin
  1539.                               { register reference }
  1540.                               { possiblities:1) local variable which }
  1541.                               { has been replaced by bp and offset   }
  1542.                               { in this case size should be valid    }
  1543.                               {              2) Indirect register    }
  1544.                               { adressing, 1st operand determines    }
  1545.                               { size.                                }
  1546.                               if (opsize = operands[2].size) or  (operands[2].size = S_NO) then
  1547.                                   p^.concat(new(pai386,op_reg_ref(instruc,
  1548.                                   opsize,operands[1].reg,newreference(operands[2].ref))))
  1549.                               else
  1550.                                   Message(assem_e_invalid_size_in_ref);
  1551.                            end;
  1552.                         OPR_CONSTANT: { const,reg }
  1553.                                Begin  { OUT const,reg }
  1554.                                  if (instruc = A_OUT) and (opsize = S_B) then
  1555.                                    p^.concat(new(pai386,op_reg_const(instruc,
  1556.                                     opsize,operands[1].reg,operands[2].val)))
  1557.                                  else
  1558.                                     Message(assem_e_invalid_size_in_ref);
  1559.                                end;
  1560.                        else { else case }
  1561.                          Begin
  1562.                            Message(assem_f_internal_error_in_concatopcode);
  1563.                          end;
  1564.                        end; { end inner case }
  1565.                      end;
  1566.                   { const,reg   }
  1567.                   { const,const }
  1568.                   { const,ref   }
  1569.                    OPR_CONSTANT:
  1570.                       case instr.operands[2].operandtype of
  1571.                       { constant, constant does not have a specific size. }
  1572.                         OPR_CONSTANT:
  1573.                            p^.concat(new(pai386,op_const_const(instruc,
  1574.                            S_NO,operands[1].val,operands[2].val)));
  1575.                         OPR_REFERENCE:
  1576.                            Begin
  1577.                               if (operands[1].val <= $ff) and
  1578.                                (operands[2].size in [S_B,S_W,S_L,S_Q,S_S]) then
  1579.                                  p^.concat(new(pai386,op_const_ref(instruc,
  1580.                                  operands[2].size,operands[1].val,
  1581.                                  newreference(operands[2].ref))))
  1582.                               else
  1583.                               if (operands[1].val <= $ffff) and
  1584.                                (operands[2].size in [S_W,S_L,S_Q,S_S]) then
  1585.                                  p^.concat(new(pai386,op_const_ref(instruc,
  1586.                                  operands[2].size,operands[1].val,
  1587.                                  newreference(operands[2].ref))))
  1588.                               else
  1589.                               if (operands[1].val <= $7fffffff) and
  1590.                                (operands[2].size in [S_L,S_Q,S_S]) then
  1591.                                  p^.concat(new(pai386,op_const_ref(instruc,
  1592.                                  operands[2].size,operands[1].val,
  1593.                                  newreference(operands[2].ref))))
  1594.                               else
  1595.                                   Message(assem_e_invalid_size_in_ref);
  1596.                            end;
  1597.                         OPR_REGISTER:
  1598.                            Begin
  1599.                               { size of opcode determined by register }
  1600.                               if (operands[1].val <= $ff) and
  1601.                                (operands[2].size in [S_B,S_W,S_L,S_Q,S_S]) then
  1602.                                  p^.concat(new(pai386,op_const_reg(instruc,
  1603.                                  operands[2].size,operands[1].val,
  1604.                                  operands[2].reg)))
  1605.                               else
  1606.                               if (operands[1].val <= $ffff) and
  1607.                                (operands[2].size in [S_W,S_L,S_Q,S_S]) then
  1608.                                  p^.concat(new(pai386,op_const_reg(instruc,
  1609.                                  operands[2].size,operands[1].val,
  1610.                                  operands[2].reg)))
  1611.                               else
  1612.                               if (operands[1].val <= $7fffffff) and
  1613.                                (operands[2].size in [S_L,S_Q,S_S]) then
  1614.                                  p^.concat(new(pai386,op_const_reg(instruc,
  1615.                                  operands[2].size,operands[1].val,
  1616.                                  operands[2].reg)))
  1617.                               else
  1618.                                Message(assem_e_invalid_opcode_size);
  1619.                            end;
  1620.                       else
  1621.                          Begin
  1622.                            Message(assem_f_internal_error_in_concatopcode);
  1623.                          end;
  1624.                       end; { end case }
  1625.                    { ref,reg     }
  1626.                    { ref,ref     }
  1627.                    OPR_REFERENCE:
  1628.                       case instr.operands[2].operandtype of
  1629.                          OPR_REGISTER:
  1630.                             if assigned(operands[1].ref.symbol) then
  1631.                             { global variable }
  1632.                             Begin
  1633.                               if instruc in [A_LEA,A_LDS,A_LES,A_LFS,A_LGS,A_LSS]
  1634.                                then
  1635.                                  p^.concat(new(pai386,op_ref_reg(instruc,
  1636.                                  S_NO,newreference(operands[1].ref),
  1637.                                  operands[2].reg)))
  1638.                               else
  1639.                               if (opsize = operands[2].size) then
  1640.                                  p^.concat(new(pai386,op_ref_reg(instruc,
  1641.                                  opsize,newreference(operands[1].ref),
  1642.                                  operands[2].reg)))
  1643.                               else
  1644.                                 Begin
  1645.                                    Message(assem_e_invalid_opcode_and_operand);
  1646.                                 end;
  1647.                             end
  1648.                             else
  1649.                             Begin
  1650.                               { register reference }
  1651.                               { possiblities:1) local variable which }
  1652.                               { has been replaced by bp and offset   }
  1653.                               { in this case size should be valid    }
  1654.                               {              2) Indirect register    }
  1655.                               { adressing, 2nd operand determines    }
  1656.                               { size.                                }
  1657.                               if (opsize = operands[2].size) or (opsize = S_NO) then
  1658.                               Begin
  1659.                                  p^.concat(new(pai386,op_ref_reg(instruc,
  1660.                                  operands[2].size,newreference(operands[1].ref),
  1661.                                  operands[2].reg)));
  1662.                               end
  1663.                               else
  1664.                                   Message(assem_e_invalid_size_in_ref);
  1665.                             end;
  1666.                          OPR_REFERENCE: { special opcodes }
  1667.                             p^.concat(new(pai386,op_ref_ref(instruc,
  1668.                             opsize,newreference(operands[1].ref),
  1669.                             newreference(operands[2].ref))));
  1670.                       else
  1671.                          Begin
  1672.                            Message(assem_f_internal_error_in_concatopcode);
  1673.                          end;
  1674.                    end; { end inner case }
  1675.                   end; { end case }
  1676.                 end; { end with }
  1677.              end; {end if movsx... }
  1678.         end;
  1679.      3: Begin
  1680.              { only imul, shld and shrd  }
  1681.              { middle must be a register }
  1682.              if (instruc in [A_SHLD,A_SHRD]) and (instr.operands[2].operandtype =
  1683.                 OPR_REGISTER) then
  1684.              Begin
  1685.                case instr.operands[2].size of
  1686.                 S_W:  if instr.operands[1].operandtype = OPR_CONSTANT then
  1687.                         Begin
  1688.                           if instr.operands[1].val <= $ff then
  1689.                             Begin
  1690.                               if instr.operands[3].size in [S_W] then
  1691.                               Begin
  1692.                                  case instr.operands[3].operandtype of
  1693.                                   OPR_REFERENCE: { MISSING !!!! } ;
  1694.                                   OPR_REGISTER:  p^.concat(new(pai386,
  1695.                                      op_const_reg_reg(instruc, S_W,
  1696.                                      instr.operands[1].val, instr.operands[2].reg,
  1697.                                      instr.operands[3].reg)));
  1698.                                  else
  1699.                                     Message(assem_e_invalid_opcode_and_operand);
  1700.                                     Message(assem_e_invalid_opcode_and_operand);
  1701.                                  end;
  1702.                               end
  1703.                               else
  1704.                                  Message(assem_e_invalid_opcode_and_operand);
  1705.                             end;
  1706.                         end
  1707.                       else
  1708.                         Message(assem_e_invalid_opcode_and_operand);
  1709.                 S_L:  if instr.operands[1].operandtype = OPR_CONSTANT then
  1710.                         Begin
  1711.                           if instr.operands[1].val <= $ff then
  1712.                             Begin
  1713.                               if instr.operands[3].size in [S_L] then
  1714.                               Begin
  1715.                                  case instr.operands[3].operandtype of
  1716.                                   OPR_REFERENCE: { MISSING !!!! } ;
  1717.                                   OPR_REGISTER:  p^.concat(new(pai386,
  1718.                                      op_const_reg_reg(instruc, S_L,
  1719.                                      instr.operands[1].val, instr.operands[2].reg,
  1720.                                      instr.operands[3].reg)));
  1721.                                  else
  1722.                                    Message(assem_e_invalid_opcode_and_operand);
  1723.                                  end;
  1724.                               end
  1725.                               else
  1726.                                 Message(assem_e_invalid_opcode_and_operand);
  1727.                             end;
  1728.                         end
  1729.                       else
  1730.                        Message(assem_e_invalid_opcode_and_operand);
  1731.                 else
  1732.                   Message(assem_e_invalid_opcode_and_operand);
  1733.                end; { end case }
  1734.              end
  1735.              else
  1736.              if (instruc in [A_IMUL]) and (instr.operands[3].operandtype
  1737.                = OPR_REGISTER) then
  1738.              Begin
  1739.                case instr.operands[3].size of
  1740.                 S_W:  if instr.operands[1].operandtype = OPR_CONSTANT then
  1741.                         Begin
  1742.                           if instr.operands[1].val <= $ffff then
  1743.                             Begin
  1744.                               if instr.operands[2].size in [S_W] then
  1745.                               Begin
  1746.                                  case instr.operands[2].operandtype of
  1747.                                   OPR_REFERENCE: { MISSING !!!! } ;
  1748.                                   OPR_REGISTER:  p^.concat(new(pai386,
  1749.                                      op_const_reg_reg(instruc, S_W,
  1750.                                      instr.operands[1].val, instr.operands[2].reg,
  1751.                                      instr.operands[3].reg)));
  1752.                                  else
  1753.                                   Message(assem_e_invalid_opcode_and_operand);
  1754.                                  end; { end case }
  1755.                               end
  1756.                               else
  1757.                                 Message(assem_e_invalid_opcode_and_operand);
  1758.                             end;
  1759.                         end
  1760.                       else
  1761.                         Message(assem_e_invalid_opcode_and_operand);
  1762.                 S_L:  if instr.operands[1].operandtype = OPR_CONSTANT then
  1763.                         Begin
  1764.                           if instr.operands[1].val <= $7fffffff then
  1765.                             Begin
  1766.                               if instr.operands[2].size in [S_L] then
  1767.                               Begin
  1768.                                  case instr.operands[2].operandtype of
  1769.                                   OPR_REFERENCE: { MISSING !!!! } ;
  1770.                                   OPR_REGISTER:  p^.concat(new(pai386,
  1771.                                      op_const_reg_reg(instruc, S_L,
  1772.                                      instr.operands[1].val, instr.operands[2].reg,
  1773.                                      instr.operands[3].reg)));
  1774.                                  else
  1775.                                    Message(assem_e_invalid_opcode_and_operand);
  1776.                                  end; { end case }
  1777.                               end
  1778.                               else
  1779.                                Message(assem_e_invalid_opcode_and_operand);
  1780.                             end;
  1781.                         end
  1782.                       else
  1783.                        Message(assem_e_invalid_opcode_and_operand);
  1784.                 else
  1785.                   Message(assem_e_invalid_middle_sized_operand);
  1786.                end; { end case }
  1787.              end { endif }
  1788.              else
  1789.                Message(assem_e_invalid_three_operand_opcode);
  1790.         end;
  1791.   end; { end case }
  1792.  end;
  1793.  end;
  1794.  
  1795.   {---------------------------------------------------------------------}
  1796.   {                     Routines for the parsing                        }
  1797.   {---------------------------------------------------------------------}
  1798.  
  1799.      procedure consume(t : tinteltoken);
  1800.  
  1801.      begin
  1802.        if t<>actasmtoken then
  1803.          Message(assem_e_syntax_error);
  1804.        actasmtoken:=gettoken;
  1805.        { if the token must be ignored, then }
  1806.        { get another token to parse.        }
  1807.        if actasmtoken = AS_NONE then
  1808.           actasmtoken := gettoken;
  1809.       end;
  1810.  
  1811.  
  1812.  
  1813.  
  1814.  
  1815.    function findregister(const s : string): tregister;
  1816.   {*********************************************************************}
  1817.   { FUNCTION findregister(s: string):tasmop;                            }
  1818.   {  Description: Determines if the s string is a valid register,       }
  1819.   {  if so returns correct tregister token, or R_NO if not found.       }
  1820.   {*********************************************************************}
  1821.    var
  1822.     i: tregister;
  1823.    begin
  1824.      findregister := R_NO;
  1825.      for i:=firstreg to lastreg do
  1826.        if s = iasmregs[i] then
  1827.        Begin
  1828.          findregister := i;
  1829.          exit;
  1830.        end;
  1831.    end;
  1832.  
  1833.  
  1834.    function findoverride(const s: string; var reg:tregister): boolean;
  1835.    var
  1836.     i: byte;
  1837.    begin
  1838.      findoverride := FALSE;
  1839.      reg := R_NO;
  1840.      for i:=0 to _count_asmoverrides do
  1841.      Begin
  1842.        if s = _asmoverrides[i] then
  1843.        begin
  1844.           reg := _overridetokens[i];
  1845.           findoverride := TRUE;
  1846.           exit;
  1847.        end;
  1848.      end;
  1849.    end;
  1850.  
  1851.    function findprefix(const s: string; var token: tasmop): boolean;
  1852.    var i: byte;
  1853.    Begin
  1854.      findprefix := FALSE;
  1855.      for i:=0 to _count_asmprefixes do
  1856.      Begin
  1857.        if s = _asmprefixes[i] then
  1858.        begin
  1859.           token := _prefixtokens[i];
  1860.           findprefix := TRUE;
  1861.           exit;
  1862.        end;
  1863.      end;
  1864.    end;
  1865.  
  1866.  
  1867.    function findsegment(const s:string): tregister;
  1868.   {*********************************************************************}
  1869.   { FUNCTION findsegment(s: string):tasmop;                             }
  1870.   {  Description: Determines if the s string is a valid segment register}
  1871.   {  if so returns correct tregister token, or R_NO if not found.       }
  1872.   {*********************************************************************}
  1873.    var
  1874.     i: tregister;
  1875.    Begin
  1876.      findsegment := R_DEFAULT_SEG;
  1877.      for i:=firstsreg to lastsreg do
  1878.        if s = iasmregs[i] then
  1879.        Begin
  1880.          findsegment := i;
  1881.          exit;
  1882.        end;
  1883.    end;
  1884.  
  1885.    function findopcode(const s: string): tasmop;
  1886.   {*********************************************************************}
  1887.   { FUNCTION findopcode(s: string): tasmop;                             }
  1888.   {  Description: Determines if the s string is a valid opcode          }
  1889.   {  if so returns correct tasmop token.                                }
  1890.   {*********************************************************************}
  1891.    var
  1892.     i: tasmop;
  1893.     j: byte;
  1894.    Begin
  1895.      findopcode := A_NONE;
  1896.      for i:=firstop to lastop do
  1897.        if  s = iasmops^[i] then
  1898.        begin
  1899.           findopcode:=i;
  1900.           exit;
  1901.        end;
  1902.      { not found yet, search for extended opcodes }
  1903.      { now, in this case, we must use the suffix  }
  1904.      { to determine the size of the instruction   }
  1905.      for j:=0 to _count_asmspecialops do
  1906.      Begin
  1907.        if s = _specialops[j] then
  1908.        Begin
  1909.          findopcode := _specialopstokens[j];
  1910.          { set the size }
  1911.          case s[length(s)] of
  1912.          'B': instr.stropsize := S_B;
  1913.          'D': instr.stropsize := S_L;
  1914.          'W': instr.stropsize := S_W;
  1915.          end;
  1916.          exit;
  1917.        end;
  1918.      end;
  1919.    end;
  1920.  
  1921.  
  1922.  
  1923.  
  1924.  
  1925.  
  1926.    Function CheckPrefix(prefix: tasmop; opcode:tasmop): Boolean;
  1927.    { Checks if the prefix is valid with the following instruction }
  1928.    { return false if not, otherwise true                          }
  1929.    Begin
  1930.      CheckPrefix := TRUE;
  1931.      Case prefix of
  1932.        A_REP,A_REPNE,A_REPE: if not (opcode in [A_SCAS,A_INS,A_OUTS,A_MOVS,
  1933.                              A_CMPS,A_LODS,A_STOS]) then
  1934.                              Begin
  1935.                                CheckPrefix := FALSE;
  1936.                                exit;
  1937.                              end;
  1938.        A_LOCK: if not (opcode in [A_BT,A_BTS,A_BTR,A_BTC,A_XCHG,A_ADD,A_OR,
  1939.                         A_ADC,A_SBB,A_AND,A_SUB,A_XOR,A_NOT,A_NEG,A_INC,A_DEC]) then
  1940.                   Begin
  1941.                      CheckPrefix := FALSE;
  1942.                      Exit;
  1943.                   end;
  1944.        A_NONE: exit; { no prefix here }
  1945.  
  1946.      else
  1947.        CheckPrefix := FALSE;
  1948.      end; { end case }
  1949.    end;
  1950.  
  1951.  
  1952.   Procedure InitAsmRef(var instr: TInstruction);
  1953.   {*********************************************************************}
  1954.   {  Description: This routine first check if the instruction is of     }
  1955.   {  type OPR_NONE, or OPR_REFERENCE , if not it gives out an error.    }
  1956.   {  If the operandtype = OPR_NONE or <> OPR_REFERENCE then it sets up  }
  1957.   {  the operand type to OPR_REFERENCE, as well as setting up the ref   }
  1958.   {  to point to the default segment.                                   }
  1959.   {*********************************************************************}
  1960.    Begin
  1961.      With instr do
  1962.      Begin
  1963.         case operands[operandnum].operandtype of
  1964.           OPR_REFERENCE: exit;
  1965.           OPR_NONE: ;
  1966.         else
  1967.           Message(assem_e_invalid_operand_type);
  1968.         end;
  1969.         operands[operandnum].operandtype := OPR_REFERENCE;
  1970.         operands[operandnum].ref.segment := R_DEFAULT_SEG;
  1971.      end;
  1972.    end;
  1973.  
  1974.    Function CheckOverride(segreg: tregister; var instr: TInstruction): Boolean;
  1975.    { Check if the override is valid, and if so then }
  1976.    { update the instr variable accordingly.         }
  1977.    Begin
  1978.      CheckOverride := FALSE;
  1979.      if instr.getinstruction in [A_MOVS,A_XLAT,A_CMPS] then
  1980.      Begin
  1981.        CheckOverride := TRUE;
  1982.        Message(assem_e_segment_override_not_supported);
  1983.      end
  1984.    end;
  1985.  
  1986.  
  1987.  
  1988.  
  1989.   Function CalculateExpression(expression: string): longint;
  1990.   var
  1991.     expr: TExprParse;
  1992.   Begin
  1993.    expr.Init;
  1994.    CalculateExpression := expr.Evaluate(expression);
  1995.    expr.Done;
  1996.   end;
  1997.  
  1998.  
  1999.  
  2000.  
  2001.  
  2002.  
  2003.  
  2004.   Function BuildRefExpression: longint;
  2005.   {*********************************************************************}
  2006.   { FUNCTION BuildExpression: longint                                   }
  2007.   {  Description: This routine calculates a constant expression to      }
  2008.   {  a given value. The return value is the value calculated from       }
  2009.   {  the expression.                                                    }
  2010.   { The following tokens (not strings) are recognized:                  }
  2011.   {    (,),SHL,SHR,/,*,NOT,OR,XOR,AND,MOD,+/-,numbers,ID to constants.  }
  2012.   {*********************************************************************}
  2013.   { ENTRY: On entry the token should be any valid expression token.     }
  2014.   { EXIT:  On Exit the token points to any token after the closing      }
  2015.   {         RBRACKET                                                    }
  2016.   { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  2017.   {  invalid tokens.                                                    }
  2018.   {*********************************************************************}
  2019.   var tempstr: string;
  2020.       expr: string;
  2021.     l : longint;
  2022.     errorflag : boolean;
  2023.   Begin
  2024.     errorflag := FALSE;
  2025.     tempstr := '';
  2026.     expr := '';
  2027.     { tell tokenizer that we are in }
  2028.     { an expression.                }
  2029.     inexpression := TRUE;
  2030.     Repeat
  2031.       Case actasmtoken of
  2032.       AS_LPAREN: Begin
  2033.                   Consume(AS_LPAREN);
  2034.                   expr := expr + '(';
  2035.                 end;
  2036.       AS_RPAREN: Begin
  2037.                   Consume(AS_RPAREN);
  2038.                   expr := expr + ')';
  2039.                 end;
  2040.       AS_SHL:    Begin
  2041.                   Consume(AS_SHL);
  2042.                   expr := expr + '<';
  2043.                 end;
  2044.       AS_SHR:    Begin
  2045.                   Consume(AS_SHR);
  2046.                   expr := expr + '>';
  2047.                 end;
  2048.       AS_SLASH:  Begin
  2049.                   Consume(AS_SLASH);
  2050.                   expr := expr + '/';
  2051.                 end;
  2052.       AS_MOD:    Begin
  2053.                   Consume(AS_MOD);
  2054.                   expr := expr + '%';
  2055.                 end;
  2056.       AS_STAR:   Begin
  2057.                   Consume(AS_STAR);
  2058.                   expr := expr + '*';
  2059.                 end;
  2060.       AS_PLUS:   Begin
  2061.                   Consume(AS_PLUS);
  2062.                   expr := expr + '+';
  2063.                 end;
  2064.       AS_MINUS:  Begin
  2065.                   Consume(AS_MINUS);
  2066.                   expr := expr + '-';
  2067.                 end;
  2068.       AS_AND:    Begin
  2069.                   Consume(AS_AND);
  2070.                   expr := expr + '&';
  2071.                 end;
  2072.       AS_NOT:    Begin
  2073.                   Consume(AS_NOT);
  2074.                   expr := expr + '~';
  2075.                 end;
  2076.       AS_XOR:    Begin
  2077.                   Consume(AS_XOR);
  2078.                   expr := expr + '^';
  2079.                 end;
  2080.       AS_OR:     Begin
  2081.                   Consume(AS_OR);
  2082.                   expr := expr + '|';
  2083.                 end;
  2084.       { End of reference }
  2085.       AS_RBRACKET: Begin
  2086.                      if not ErrorFlag then
  2087.                         BuildRefExpression := CalculateExpression(expr)
  2088.                      else
  2089.                         BuildRefExpression := 0;
  2090.                      Consume(AS_RBRACKET);
  2091.                      { no longer in an expression }
  2092.                      inexpression := FALSE;
  2093.                      exit;
  2094.                   end;
  2095.       AS_ID:
  2096.                 Begin
  2097.                   if NOT SearchIConstant(actasmpattern,l) then
  2098.                   Begin
  2099.                     Message1(assem_e_invalid_const_symbol,actasmpattern);
  2100.                     l := 0;
  2101.                   end;
  2102.                   str(l, tempstr);
  2103.                   expr := expr + tempstr;
  2104.                   Consume(AS_ID);
  2105.                 end;
  2106.       AS_INTNUM:  Begin
  2107.                    expr := expr + actasmpattern;
  2108.                    Consume(AS_INTNUM);
  2109.                  end;
  2110.       AS_BINNUM:  Begin
  2111.                       tempstr := BinaryToDec(actasmpattern);
  2112.                       if tempstr = '' then
  2113.                        Message(assem_f_error_converting_bin);
  2114.                       expr:=expr+tempstr;
  2115.                       Consume(AS_BINNUM);
  2116.                  end;
  2117.  
  2118.       AS_HEXNUM: Begin
  2119.                     tempstr := HexToDec(actasmpattern);
  2120.                     if tempstr = '' then
  2121.                      Message(assem_f_error_converting_hex);
  2122.                     expr:=expr+tempstr;
  2123.                     Consume(AS_HEXNUM);
  2124.                 end;
  2125.       AS_OCTALNUM: Begin
  2126.                     tempstr := OctalToDec(actasmpattern);
  2127.                     if tempstr = '' then
  2128.                      Message(assem_f_error_converting_octal);
  2129.                     expr:=expr+tempstr;
  2130.                     Consume(AS_OCTALNUM);
  2131.                   end;
  2132.       else
  2133.         Begin
  2134.           { write error only once. }
  2135.           if not errorflag then
  2136.            Message(assem_e_invalid_constant_expression);
  2137.           BuildRefExpression := 0;
  2138.           if actasmtoken in [AS_COMMA,AS_SEPARATOR] then exit;
  2139.           { consume tokens until we find COMMA or SEPARATOR }
  2140.           Consume(actasmtoken);
  2141.           errorflag := TRUE;
  2142.         end;
  2143.       end;
  2144.     Until false;
  2145.   end;
  2146.  
  2147.  
  2148.  
  2149.   Procedure BuildRecordOffset(var instr: TInstruction; varname: string);
  2150.   {*********************************************************************}
  2151.   { PROCEDURE BuildRecordOffset(var Instr: TInstruction)                }
  2152.   { Description: This routine takes care of field specifiers of records }
  2153.   {  and/or variables in asm operands. It updates the offset accordingly}
  2154.   {*********************************************************************}
  2155.   { ENTRY: On entry the token should be DOT.                            }
  2156.   {    name: should be the name of the variable to be expanded. '' if   }
  2157.   {     no variabled specified.                                         }
  2158.   { EXIT:  On Exit the token points to SEPARATOR or COMMA.              }
  2159.   { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  2160.   {  invalid tokens.                                                    }
  2161.   {*********************************************************************}
  2162.   var
  2163.     firstpass: boolean;
  2164.     offset: longint;
  2165.     basetypename : string;
  2166.   Begin
  2167.     basetypename := '';
  2168.     firstpass := TRUE;
  2169.     { // .ID[REG].ID ...   // }
  2170.     { // .ID.ID...         // }
  2171.     Consume(AS_DOT);
  2172.     Repeat
  2173.       case actasmtoken of
  2174.         AS_ID: Begin
  2175.                   InitAsmRef(instr);
  2176.                   { // var_name.typefield.typefield // }
  2177.                   if (varname <> '') then
  2178.                   Begin
  2179.                     if not GetVarOffset(varname,actasmpattern,offset) then
  2180.                     Begin
  2181.                       Message1(assem_e_unknown_id,actasmpattern);
  2182.                     end
  2183.                     else
  2184.                       Inc(instr.operands[operandnum].ref.offset,Offset);
  2185.                   end
  2186.                   else
  2187.                  {    [ref].var_name.typefield.typefield ...                }
  2188.                  {    [ref].var_name[reg]                                   }
  2189.                   if not assigned(instr.operands[operandnum].ref.symbol) and
  2190.                     firstpass then
  2191.                   Begin
  2192.                      if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2193.                      Begin
  2194.                        { type field ? }
  2195.                        basetypename := actasmpattern;
  2196.                      end
  2197.                      else
  2198.                        varname := actasmpattern;
  2199.                     end
  2200.                   else
  2201.                   if firstpass then
  2202.                  {    [ref].typefield.typefield ...                         }
  2203.                  {    where the first typefield must specifiy the base      }
  2204.                  {    object or record type.                                }
  2205.                   Begin
  2206.                      basetypename := actasmpattern;
  2207.                   end
  2208.                   else
  2209.                  {    [ref].typefield.typefield ...                         }
  2210.                  {  basetpyename is already set up... now look for fields.  }
  2211.                   Begin
  2212.                      if not GetTypeOffset(basetypename,actasmpattern,Offset) then
  2213.                      Begin
  2214.                       Message1(assem_e_unknown_id,actasmpattern);
  2215.                      end
  2216.                      else
  2217.                        Inc(instr.operands[operandnum].ref.offset,Offset);
  2218.                   end;
  2219.                   Consume(AS_ID);
  2220.                  { Take care of index register on this variable }
  2221.                  if actasmtoken = AS_LBRACKET then
  2222.                  Begin
  2223.                    Consume(AS_LBRACKET);
  2224.                    Case actasmtoken of
  2225.                      AS_REGISTER: Begin
  2226.                                    if instr.operands[operandnum].ref.index <> R_NO then
  2227.                                     Message(assem_e_defining_index_more_than_once);
  2228.                                    instr.operands[operandnum].ref.index :=
  2229.                                       findregister(actasmpattern);
  2230.                                    Consume(AS_REGISTER);
  2231.                                   end;
  2232.                     else
  2233.                      Begin
  2234.                       { add offsets , assuming these are constant expressions... }
  2235.                       Inc(instr.operands[operandnum].ref.offset,BuildRefExpression);
  2236.                      end;
  2237.                    end;
  2238.                    Consume(AS_RBRACKET);
  2239.                  end;
  2240.                  { Here we should either have AS_DOT, AS_SEPARATOR or AS_COMMA }
  2241.                  if actasmtoken = AS_DOT then
  2242.                     Consume(AS_DOT);
  2243.                  firstpass := FALSE;
  2244.                  Offset := 0;
  2245.               end;
  2246.         AS_SEPARATOR: exit;
  2247.         AS_COMMA: exit;
  2248.       else
  2249.        Begin
  2250.          Message(assem_e_invalid_field_specifier);
  2251.          Consume(actasmtoken);
  2252.          firstpass := FALSE;
  2253.        end;
  2254.       end; { end case }
  2255.     Until (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA);
  2256.   end;
  2257.  
  2258.  
  2259.   Function BuildExpression: longint;
  2260.   {*********************************************************************}
  2261.   { FUNCTION BuildExpression: longint                                   }
  2262.   {  Description: This routine calculates a constant expression to      }
  2263.   {  a given value. The return value is the value calculated from       }
  2264.   {  the expression.                                                    }
  2265.   { The following tokens (not strings) are recognized:                  }
  2266.   {    (,),SHL,SHR,/,*,NOT,OR,XOR,AND,MOD,+/-,numbers,ID to constants.  }
  2267.   {*********************************************************************}
  2268.   { ENTRY: On entry the token should be any valid expression token.     }
  2269.   { EXIT:  On Exit the token points to either COMMA or SEPARATOR        }
  2270.   { ERROR RECOVERY: Tries to find COMMA or SEPARATOR token by consuming }
  2271.   {  invalid tokens.                                                    }
  2272.   {*********************************************************************}
  2273.   var expr: string;
  2274.       tempstr: string;
  2275.       l : longint;
  2276.       errorflag: boolean;
  2277.   Begin
  2278.     errorflag := FALSE;
  2279.     expr := '';
  2280.     tempstr := '';
  2281.     { tell tokenizer that we are in an expression. }
  2282.     inexpression := TRUE;
  2283.     Repeat
  2284.       Case actasmtoken of
  2285.       AS_LPAREN: Begin
  2286.                   Consume(AS_LPAREN);
  2287.                   expr := expr + '(';
  2288.                 end;
  2289.       AS_RPAREN: Begin
  2290.                   Consume(AS_RPAREN);
  2291.                   expr := expr + ')';
  2292.                 end;
  2293.       AS_SHL:    Begin
  2294.                   Consume(AS_SHL);
  2295.                   expr := expr + '<';
  2296.                 end;
  2297.       AS_SHR:    Begin
  2298.                   Consume(AS_SHR);
  2299.                   expr := expr + '>';
  2300.                 end;
  2301.       AS_SLASH:  Begin
  2302.                   Consume(AS_SLASH);
  2303.                   expr := expr + '/';
  2304.                 end;
  2305.       AS_MOD:    Begin
  2306.                   Consume(AS_MOD);
  2307.                   expr := expr + '%';
  2308.                 end;
  2309.       AS_STAR:   Begin
  2310.                   Consume(AS_STAR);
  2311.                   expr := expr + '*';
  2312.                 end;
  2313.       AS_PLUS:   Begin
  2314.                   Consume(AS_PLUS);
  2315.                   expr := expr + '+';
  2316.                 end;
  2317.       AS_MINUS:  Begin
  2318.                   Consume(AS_MINUS);
  2319.                   expr := expr + '-';
  2320.                 end;
  2321.       AS_AND:    Begin
  2322.                   Consume(AS_AND);
  2323.                   expr := expr + '&';
  2324.                 end;
  2325.       AS_NOT:    Begin
  2326.                   Consume(AS_NOT);
  2327.                   expr := expr + '~';
  2328.                 end;
  2329.       AS_XOR:    Begin
  2330.                   Consume(AS_XOR);
  2331.                   expr := expr + '^';
  2332.                 end;
  2333.       AS_OR:     Begin
  2334.                   Consume(AS_OR);
  2335.                   expr := expr + '|';
  2336.                 end;
  2337.       AS_ID:    Begin
  2338.                   if NOT SearchIConstant(actasmpattern,l) then
  2339.                   Begin
  2340.                     Message1(assem_e_invalid_const_symbol,actasmpattern);
  2341.                     l := 0;
  2342.                   end;
  2343.                   str(l, tempstr);
  2344.                   expr := expr + tempstr;
  2345.                   Consume(AS_ID);
  2346.                 end;
  2347.       AS_INTNUM:  Begin
  2348.                    expr := expr + actasmpattern;
  2349.                    Consume(AS_INTNUM);
  2350.                  end;
  2351.       AS_BINNUM:  Begin
  2352.                       tempstr := BinaryToDec(actasmpattern);
  2353.                       if tempstr = '' then
  2354.                        Message(assem_f_error_converting_bin);
  2355.                       expr:=expr+tempstr;
  2356.                       Consume(AS_BINNUM);
  2357.                  end;
  2358.  
  2359.       AS_HEXNUM: Begin
  2360.                     tempstr := HexToDec(actasmpattern);
  2361.                     if tempstr = '' then
  2362.                      Message(assem_f_error_converting_hex);
  2363.                     expr:=expr+tempstr;
  2364.                     Consume(AS_HEXNUM);
  2365.                 end;
  2366.       AS_OCTALNUM: Begin
  2367.                     tempstr := OctalToDec(actasmpattern);
  2368.                     if tempstr = '' then
  2369.                      Message(assem_f_error_converting_octal);
  2370.                     expr:=expr+tempstr;
  2371.                     Consume(AS_OCTALNUM);
  2372.                   end;
  2373.       { go to next term }
  2374.       AS_COMMA: Begin
  2375.                   if not ErrorFlag then
  2376.                     BuildExpression := CalculateExpression(expr)
  2377.                   else
  2378.                     BuildExpression := 0;
  2379.                   inexpression := FALSE;
  2380.                   Exit;
  2381.                end;
  2382.       { go to next symbol }
  2383.       AS_SEPARATOR: Begin
  2384.                       if not ErrorFlag then
  2385.                         BuildExpression := CalculateExpression(expr)
  2386.                       else
  2387.                         BuildExpression := 0;
  2388.                       inexpression := FALSE;
  2389.                       Exit;
  2390.                    end;
  2391.       else
  2392.         Begin
  2393.           { only write error once. }
  2394.           if not errorflag then
  2395.            Message(assem_e_invalid_constant_expression);
  2396.           { consume tokens until we find COMMA or SEPARATOR }
  2397.           Consume(actasmtoken);
  2398.           errorflag := TRUE;
  2399.         End;
  2400.       end;
  2401.     Until false;
  2402.   end;
  2403.  
  2404.  
  2405.  
  2406.  
  2407.   Procedure BuildScaling(Var instr: TInstruction);
  2408.   {*********************************************************************}
  2409.   {  Takes care of parsing expression starting from the scaling value   }
  2410.   {  up to and including possible field specifiers.                     }
  2411.   { EXIT CONDITION:  On exit the routine should point to  AS_SEPARATOR  }
  2412.   { or AS_COMMA. On entry should point to AS_STAR token.                }
  2413.   {*********************************************************************}
  2414.   var str:string;
  2415.       l: longint;
  2416.       code: integer;
  2417.   Begin
  2418.      Consume(AS_STAR);
  2419.      if (instr.operands[operandnum].ref.scalefactor <> 0)
  2420.      and (instr.operands[operandnum].ref.scalefactor <> 1) then
  2421.      Begin
  2422.          Message(assem_f_internal_error_in_buildscale);
  2423.      end;
  2424.      case actasmtoken of
  2425.         AS_INTNUM: str := actasmpattern;
  2426.         AS_HEXNUM: str := HexToDec(actasmpattern);
  2427.         AS_BINNUM: str := BinaryToDec(actasmpattern);
  2428.         AS_OCTALNUM: str := OctalToDec(actasmpattern);
  2429.      else
  2430.         Message(assem_e_syntax_error);
  2431.      end;
  2432.      val(str, l, code);
  2433.      if code <> 0 then
  2434.        Message(assem_e_invalid_scaling_factor);
  2435.      if ((l = 2) or (l = 4) or (l = 8) or (l = 1)) and (code = 0) then
  2436.      begin
  2437.         instr.operands[operandnum].ref.scalefactor := l;
  2438.      end
  2439.      else
  2440.      Begin
  2441.         Message(assem_e_invalid_scaling_value);
  2442.         instr.operands[operandnum].ref.scalefactor := 0;
  2443.      end;
  2444.      if instr.operands[operandnum].ref.index = R_NO then
  2445.      Begin
  2446.         Message(assem_e_scaling_value_only_allowed_with_index);
  2447.         instr.operands[operandnum].ref.scalefactor := 0;
  2448.      end;
  2449.     { Consume the scaling number }
  2450.     Consume(actasmtoken);
  2451.     case actasmtoken of
  2452.         { //  [...*SCALING-expr] ... // }
  2453.         AS_MINUS: Begin
  2454.                     if instr.operands[operandnum].ref.offset <> 0 then
  2455.                      Message(assem_f_internal_error_in_buildscale);
  2456.                     instr.operands[operandnum].ref.offset :=
  2457.                         BuildRefExpression;
  2458.                   end;
  2459.         { //  [...*SCALING+expr] ... // }
  2460.         AS_PLUS: Begin
  2461.                     if instr.operands[operandnum].ref.offset <> 0 then
  2462.                      Message(assem_f_internal_error_in_buildscale);
  2463.                     instr.operands[operandnum].ref.offset :=
  2464.                          BuildRefExpression;
  2465.                     end;
  2466.         { //  [...*SCALING] ... // }
  2467.         AS_RBRACKET: Consume(AS_RBRACKET);
  2468.     else
  2469.        Message(assem_e_invalid_scaling_value);
  2470.     end;
  2471.     { // .Field.Field ... or separator/comma // }
  2472.     Case actasmtoken of
  2473.      AS_DOT: BuildRecordOffset(instr,'');
  2474.      AS_COMMA, AS_SEPARATOR: ;
  2475.     else
  2476.       Message(assem_e_syntax_error);
  2477.     end;
  2478.   end;
  2479.  
  2480.  
  2481.  
  2482.   Procedure BuildReference(var instr: TInstruction);
  2483.   {*********************************************************************}
  2484.   { EXIT CONDITION:  On exit the routine should point to either the     }
  2485.   {       AS_COMMA or AS_SEPARATOR token.                               }
  2486.   {   On entry: contains the register after the opening bracket if any. }
  2487.   {*********************************************************************}
  2488.   var
  2489.     reg:string;
  2490.     segreg: boolean;
  2491.     negative: boolean;
  2492.     expr: string;
  2493.   Begin
  2494.      expr := '';
  2495.      if instr.operands[operandnum].operandtype <> OPR_REFERENCE then
  2496.      Begin
  2497.        Message(assem_e_syn_no_ref_with_brackets);
  2498.        InitAsmRef(instr);
  2499.        consume(AS_REGISTER);
  2500.      end
  2501.      else
  2502.      Begin
  2503.        { save the reg }
  2504.        reg := actasmpattern;
  2505.        { is the syntax of the form: [REG:REG...] }
  2506.        consume(AS_REGISTER);
  2507.        if actasmtoken = AS_COLON then
  2508.        begin
  2509.          segreg := TRUE;
  2510.          Message(assem_e_expression_form_not_supported);
  2511.          if instr.operands[operandnum].ref.segment <> R_NO then
  2512.           Message(assem_e_defining_seg_more_than_once);
  2513.          instr.operands[operandnum].ref.segment := findsegment(reg);
  2514.          { Here we should process the syntax of the form   }
  2515.          { [reg:reg...]                                    }
  2516.          {!!!!!!!!!!!!!!!!!!!!!!!!                         }
  2517.        end
  2518.        { This is probably of the following syntax: }
  2519.        { SREG:[REG...] where SReg: is optional.    }
  2520.        { Therefore we immediately say that reg     }
  2521.        { is the base.                              }
  2522.        else
  2523.        Begin
  2524.          if instr.operands[operandnum].ref.base <> R_NO then
  2525.           Message(assem_e_defining_base_more_than_once);
  2526.          instr.operands[operandnum].ref.base := findregister(reg);
  2527.        end;
  2528.        { we process this type of syntax immediately... }
  2529.        case actasmtoken of
  2530.  
  2531.           { //  REG:[REG].Field.Field ...     // }
  2532.           { //  REG:[REG].Field[REG].Field... // }
  2533.          AS_RBRACKET: Begin
  2534.                        Consume(AS_RBRACKET);
  2535.                        { check for record fields }
  2536.                        if actasmtoken = AS_DOT then
  2537.                           BuildRecordOffset(instr,'');
  2538.                        if (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA) then
  2539.                          exit
  2540.                        else
  2541.                          Message(assem_e_syn_reference);
  2542.                      end;
  2543.           { //  REG:[REG +/- ...].Field.Field ... // }
  2544.          AS_PLUS,AS_MINUS: Begin
  2545.                             if actasmtoken = AS_MINUS then
  2546.                             Begin
  2547.                                expr := '-';
  2548.                                negative := TRUE
  2549.                             end
  2550.                             else
  2551.                             Begin
  2552.                                negative := FALSE;
  2553.                                expr := '+';
  2554.                             end;
  2555.                             Consume(actasmtoken);
  2556.                             { // REG:[REG+REG+/-...].Field.Field // }
  2557.                             if actasmtoken = AS_REGISTER then
  2558.                             Begin
  2559.                               if negative then
  2560.                                 Message(assem_e_negative_index_register);
  2561.                               if instr.operands[operandnum].ref.index <> R_NO then
  2562.                                 Message(assem_e_defining_index_more_than_once);
  2563.                               instr.operands[operandnum].ref.index := findregister(actasmpattern);
  2564.                               Consume(AS_REGISTER);
  2565.                               case actasmtoken of
  2566.                                 AS_RBRACKET: { // REG:[REG+REG].Field.Field... // }
  2567.                                             Begin
  2568.                                               Consume(AS_RBRACKET);
  2569.                                               Case actasmtoken of
  2570.                                                  AS_DOT: BuildRecordOffset(instr,'');
  2571.                                                  AS_COMMA,AS_SEPARATOR: exit;
  2572.                                               else
  2573.                                                 Message(assem_e_syntax_error);
  2574.                                               end
  2575.                                              end;
  2576.                                 AS_PLUS,AS_MINUS: { // REG:[REG+REG+/-expr].Field.Field... // }
  2577.                                                 Begin
  2578.                                                   if instr.operands[operandnum].ref.offset <> 0 then
  2579.                                                    Message(assem_f_internal_error_in_buildreference);
  2580.                                                   instr.operands[operandnum].ref.offset :=
  2581.                                                       BuildRefExpression;
  2582.                                                   case actasmtoken of
  2583.                                                     AS_DOT: BuildRecordOffset(instr,'');
  2584.                                                     AS_COMMA,AS_SEPARATOR: ;
  2585.                                                   else
  2586.                                                     Message(assem_e_syntax_error);
  2587.                                                   end; { end case }
  2588.                                                 end;
  2589.                                 AS_STAR: Begin  { // REG:[REG+REG*SCALING...].Field.Field... // }
  2590.                                              BuildScaling(instr);
  2591.                                          end;
  2592.                                 else
  2593.                                 Begin
  2594.                                   Message(assem_e_syntax_error);
  2595.                                 end;
  2596.                               end; { end case }
  2597.                             end
  2598.                             else if actasmtoken = AS_STAR then
  2599.                             { // REG:[REG*SCALING ... ]     // }
  2600.                             Begin
  2601.                               BuildScaling(instr);
  2602.                             end
  2603.                             else
  2604.                             { // REG:[REG+expr].Field.Field // }
  2605.                              Begin
  2606.                                if instr.operands[operandnum].ref.offset <> 0 then
  2607.                                 Message(assem_f_internal_error_in_buildreference);
  2608.                                instr.operands[operandnum].ref.offset := BuildRefExpression;
  2609.                                case actasmtoken of
  2610.                                   AS_DOT: BuildRecordOffset(instr,'');
  2611.                                   AS_COMMA,AS_SEPARATOR: ;
  2612.                                 else
  2613.                                   Message(assem_e_syntax_error);
  2614.                                end; { end case }
  2615.                              end; { end if }
  2616.                          end; { end this case }
  2617.      { //  REG:[REG*scaling] ... // }
  2618.          AS_STAR: Begin
  2619.                      BuildScaling(instr);
  2620.                  end;
  2621.        end;
  2622.      end; { end outer if }
  2623.   end;
  2624.  
  2625.  
  2626.   Procedure BuildBracketExpression(var Instr: TInstruction; var_prefix: boolean);
  2627.   {*********************************************************************}
  2628.   { PROCEDURE BuildBracketExpression                                    }
  2629.   {  Description: This routine builds up an expression after a LBRACKET }
  2630.   {  token is encountered.                                              }
  2631.   {   On entry actasmtoken should be equal to AS_LBRACKET.              }
  2632.   {  var_prefix : Should be set to true if variable identifier has      }
  2633.   {    been defined, such as in ID[                                     }
  2634.   {*********************************************************************}
  2635.   { EXIT CONDITION:  On exit the routine should point to either the     }
  2636.   {       AS_COMMA or AS_SEPARATOR token.                               }
  2637.   {*********************************************************************}
  2638.   var
  2639.     l:longint;
  2640.   Begin
  2641.      Consume(AS_LBRACKET);
  2642.      initAsmRef(instr);
  2643.      Case actasmtoken of
  2644.          { // Constant reference expression OR variable reference expression // }
  2645.          AS_ID: Begin
  2646.                 if actasmpattern[1] = '@' then
  2647.                  Message(assem_e_local_symbol_not_allowed_as_ref);
  2648.                 if SearchIConstant(actasmpattern,l) then
  2649.                  Begin
  2650.                    { if there was a variable prefix then }
  2651.                    { add to offset                       }
  2652.                    If var_prefix then
  2653.                     Begin
  2654.                         Inc(instr.operands[operandnum].ref.offset,  BuildRefExpression);
  2655.                     end
  2656.                    else
  2657.                      instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2658.                    if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2659.                       Message(assem_e_invalid_operand_in_bracket_expression);
  2660.                  end
  2661.                 else if NOT var_prefix then
  2662.                  Begin
  2663.                     InitAsmRef(instr);
  2664.                     if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2665.                      Message1(assem_e_unknown_id,actasmpattern);
  2666.                     Consume(AS_ID);
  2667.                    { is there a constant expression following }
  2668.                    { the variable name?                       }
  2669.                    if actasmtoken <> AS_RBRACKET then
  2670.                     Begin
  2671.                       Inc(instr.operands[operandnum].ref.offset, BuildRefExpression);
  2672.                     end
  2673.                    else
  2674.                       Consume(AS_RBRACKET);
  2675.                  end
  2676.                  else
  2677.                    Message1(assem_e_invalid_symbol_name,actasmpattern);
  2678.                 end;
  2679.                { Here we handle the special case in tp where   }
  2680.                { the + operator is allowed with reg and var    }
  2681.                { references, such as in mov al, byte ptr [+bx] }
  2682.          AS_PLUS: Begin
  2683.                    Consume(AS_PLUS);
  2684.                    Case actasmtoken of
  2685.                      AS_REGISTER: Begin
  2686.                                    BuildReference(instr);
  2687.                                  end;
  2688.                      AS_ID: Begin
  2689.                              if actasmpattern[1] = '@' then
  2690.                                Message(assem_e_local_symbol_not_allowed_as_ref);
  2691.                              if SearchIConstant(actasmpattern,l) then
  2692.                                Begin
  2693.                                  { if there was a variable prefix then }
  2694.                                  { add to offset                       }
  2695.                                  If var_prefix then
  2696.                                   Begin
  2697.                                     Inc(instr.operands[operandnum].ref.offset,
  2698.                                      BuildRefExpression);
  2699.                                   end
  2700.                                  else
  2701.                                    instr.operands[operandnum].ref.offset :=
  2702.                                     BuildRefExpression;
  2703.                                  if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2704.                                    Message(assem_e_invalid_operand_in_bracket_expression);
  2705.                                end
  2706.                              else if NOT var_prefix then
  2707.                                Begin
  2708.                                InitAsmRef(instr);
  2709.                                if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2710.                                 Message1(assem_e_unknown_id,actasmpattern);
  2711.                                Consume(AS_ID);
  2712.                                { is there a constant expression following }
  2713.                                { the variable name?                       }
  2714.                                  if actasmtoken <> AS_RBRACKET then
  2715.                                    Begin
  2716.                                     Inc(instr.operands[operandnum].ref.offset,
  2717.                                       BuildRefExpression);
  2718.                                    end
  2719.                                  else
  2720.                                    Consume(AS_RBRACKET);
  2721.                                end
  2722.                              else
  2723.                                Message1(assem_e_invalid_symbol_name,actasmpattern);
  2724.                            end;
  2725.                      { // Constant reference expression //  }
  2726.                    AS_INTNUM,AS_BINNUM,AS_OCTALNUM,
  2727.                    AS_HEXNUM: Begin
  2728.                                { if there was a variable prefix then }
  2729.                                { add to offset instead.              }
  2730.                                If var_prefix then
  2731.                                 Begin
  2732.                                   Inc(instr.operands[operandnum].ref.offset,  BuildRefExpression);
  2733.                                 end
  2734.                                else
  2735.                                Begin
  2736.                                  instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2737.                                end;
  2738.                                if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2739.                                   Message(assem_e_invalid_operand_in_bracket_expression);
  2740.                              end;
  2741.                     else
  2742.                       Message(assem_e_syntax_error);
  2743.                    end;
  2744.                  end;
  2745.          { // Constant reference expression //  }
  2746.          AS_MINUS,AS_NOT,AS_LPAREN:
  2747.                      Begin
  2748.                        { if there was a variable prefix then }
  2749.                        { add to offset instead.              }
  2750.                        If var_prefix then
  2751.                          Begin
  2752.                               Inc(instr.operands[operandnum].ref.offset,  BuildRefExpression);
  2753.                          end
  2754.                         else
  2755.                          Begin
  2756.                            instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2757.                          end;
  2758.                        if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2759.                           Message(assem_e_invalid_operand_in_bracket_expression);
  2760.                      end;
  2761.          { // Constant reference expression //  }
  2762.          AS_INTNUM,AS_OCTALNUM,AS_BINNUM,AS_HEXNUM: Begin
  2763.                        { if there was a variable prefix then }
  2764.                        { add to offset instead.              }
  2765.                        If var_prefix then
  2766.                          Begin
  2767.                               Inc(instr.operands[operandnum].ref.offset,  BuildRefExpression);
  2768.                          end
  2769.                         else
  2770.                          Begin
  2771.                            instr.operands[operandnum].ref.offset :=BuildRefExpression;
  2772.                          end;
  2773.                        if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2774.                           Message(assem_e_invalid_operand_in_bracket_expression);
  2775.                    end;
  2776.          { // Variable reference expression // }
  2777.          AS_REGISTER: BuildReference(instr);
  2778.      else
  2779.        Begin
  2780.          Message(assem_e_invalid_reference_syntax);
  2781.          while (actasmtoken <> AS_SEPARATOR) do
  2782.            Consume(actasmtoken);
  2783.        end;
  2784.      end; { end case }
  2785.   end;
  2786.  
  2787.  
  2788.   Procedure BuildOperand(var instr: TInstruction);
  2789.   {*********************************************************************}
  2790.   { EXIT CONDITION:  On exit the routine should point to either the     }
  2791.   {       AS_COMMA or AS_SEPARATOR token.                               }
  2792.   {*********************************************************************}
  2793.   var
  2794.     tempstr: string;
  2795.     expr: string;
  2796.     lab: Pasmlabel;
  2797.     l : longint;
  2798.     hl: plabel;
  2799.   Begin
  2800.    tempstr := '';
  2801.    expr := '';
  2802.    case actasmtoken of
  2803.    { // Constant expression //  }
  2804.      AS_PLUS,AS_MINUS,AS_NOT,AS_LPAREN:
  2805.                                   Begin
  2806.                                      if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_CONSTANT]) then
  2807.                                         Message(assem_e_invalid_operand_type);
  2808.                                      instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2809.                                      instr.operands[operandnum].val :=BuildExpression;
  2810.                                    end;
  2811.    { // Constant expression //  }
  2812.      AS_STRING:   Begin
  2813.                     if not (instr.operands[operandnum].operandtype in [OPR_NONE]) then
  2814.                        Message(assem_e_invalid_operand_type);
  2815.                     instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2816.                     if not PadZero(actasmpattern,4) then
  2817.                      Message1(assem_e_invalid_string_as_opcode_operand,actasmpattern);
  2818.                     instr.operands[operandnum].val :=
  2819.                       ord(actasmpattern[4]) + ord(actasmpattern[3]) shl 8 +
  2820.                        Ord(actasmpattern[2]) shl 16 + ord(actasmpattern[1])
  2821.                         shl 24;
  2822.                     Consume(AS_STRING);
  2823.                     Case actasmtoken of
  2824.                        AS_COMMA, AS_SEPARATOR: ;
  2825.                     else
  2826.                       Message(assem_e_invalid_string_expression);
  2827.                     end; { end case }
  2828.                  end;
  2829.    { // Constant expression //  }
  2830.      AS_INTNUM,AS_BINNUM,
  2831.      AS_OCTALNUM,
  2832.      AS_HEXNUM:     Begin
  2833.                       if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_CONSTANT]) then
  2834.                          Message(assem_e_invalid_operand_type);
  2835.                       instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2836.                       instr.operands[operandnum].val :=BuildExpression;
  2837.                     end;
  2838.    { // A constant expression, or a Variable ref. // }
  2839.      AS_ID:  Begin
  2840.               if actasmpattern[1] = '@' then
  2841.               { // Label or Special symbol reference // }
  2842.               Begin
  2843.                  if actasmpattern = '@RESULT' then
  2844.                    Begin
  2845.                       InitAsmRef(instr);
  2846.                       SetUpResult(instr,operandnum);
  2847.                    end
  2848.                  else
  2849.                   if (actasmpattern = '@CODE') or (actasmpattern = '@DATA') then
  2850.                       Message(assem_w_CODE_and_DATA_not_supported)
  2851.                    else
  2852.                   Begin
  2853.                     delete(actasmpattern,1,1);
  2854.                     if actasmpattern = '' then
  2855.                       Message(assem_e_null_label_ref_not_allowed);
  2856.                     lab := labellist.search(actasmpattern);
  2857.                     { check if the label is already defined   }
  2858.                     { if so, we then check if the plabel is   }
  2859.                     { non-nil, if so we add it to instruction }
  2860.                     if assigned(lab) then
  2861.                      Begin
  2862.                      if assigned(lab^.lab) then
  2863.                        Begin
  2864.                          instr.operands[operandnum].operandtype := OPR_LABINSTR;
  2865.                          instr.operands[operandnum].hl := lab^.lab;
  2866.                          instr.labeled := TRUE;
  2867.                        end;
  2868.                      end
  2869.                     else
  2870.                     { the label does not exist, create it }
  2871.                     { emit the opcode, but set that the   }
  2872.                     { label has not been emitted          }
  2873.                      Begin
  2874.                         getlabel(hl);
  2875.                         labellist.insert(actasmpattern,hl,FALSE);
  2876.                         instr.operands[operandnum].operandtype := OPR_LABINSTR;
  2877.                         instr.operands[operandnum].hl := hl;
  2878.                         instr.labeled := TRUE;
  2879.                      end;
  2880.                   end;
  2881.                 Consume(AS_ID);
  2882.                 if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2883.                 Begin
  2884.                   Message(assem_e_syntax_error);
  2885.                 end;
  2886.               end
  2887.               { probably a variable or normal expression }
  2888.               { or a procedure (such as in CALL ID)      }
  2889.               else
  2890.                Begin
  2891.                    { is it a constant ? }
  2892.                    if SearchIConstant(actasmpattern,l) then
  2893.                    Begin
  2894.                       if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_CONSTANT]) then
  2895.                        Message(assem_e_invalid_operand_type);
  2896.                       instr.operands[operandnum].operandtype := OPR_CONSTANT;
  2897.                       instr.operands[operandnum].val :=BuildExpression;
  2898.                     end
  2899.                    else { is it a label variable ? }
  2900.                     Begin
  2901.                      { // ID[ , ID.Field.Field or simple ID // }
  2902.                      { check if this is a label, if so then }
  2903.                      { emit it as a label.                  }
  2904.                      if SearchLabel(actasmpattern,hl) then
  2905.                      Begin
  2906.                         instr.operands[operandnum].operandtype := OPR_LABINSTR;
  2907.                         instr.operands[operandnum].hl := hl;
  2908.                         instr.labeled := TRUE;
  2909.                         Consume(AS_ID);
  2910.                         if not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) then
  2911.                           Message(assem_e_syntax_error);
  2912.                      end
  2913.                      else
  2914.                      { is it a normal variable ? }
  2915.                      Begin
  2916.                       initAsmRef(instr);
  2917.                       if not CreateVarInstr(instr,actasmpattern,operandnum) then
  2918.                       Begin
  2919.                          { not a variable.. }
  2920.                          { check special variables.. }
  2921.                          if actasmpattern = 'SELF' then
  2922.                           { special self variable }
  2923.                          Begin
  2924.                            if assigned(procinfo._class) then
  2925.                              Begin
  2926.                                instr.operands[operandnum].ref.offset := procinfo.ESI_offset;
  2927.                                instr.operands[operandnum].ref.base := procinfo.framepointer;
  2928.                              end
  2929.                            else
  2930.                              Message(assem_e_cannot_use_SELF_outside_a_method);
  2931.                          end
  2932.                          else
  2933.                            Message1(assem_e_unknown_id,actasmpattern);
  2934.                       end;
  2935.                       expr := actasmpattern;
  2936.                       Consume(AS_ID);
  2937.                       case actasmtoken of
  2938.                            AS_LBRACKET: { indexing }
  2939.                                         BuildBracketExpression(instr,TRUE);
  2940.                            AS_DOT: BuildRecordOffset(instr,expr);
  2941.  
  2942.                            AS_SEPARATOR,AS_COMMA: ;
  2943.                       else
  2944.                            Message(assem_e_syntax_error);
  2945.                       end;
  2946.                      end;
  2947.                     end;
  2948.                end;
  2949.             end;
  2950.    { // Register, a variable reference or a constant reference // }
  2951.      AS_REGISTER: Begin
  2952.                    { save the type of register used. }
  2953.                    tempstr := actasmpattern;
  2954.                    Consume(AS_REGISTER);
  2955.                    if actasmtoken = AS_COLON then
  2956.                    Begin
  2957.                       Consume(AS_COLON);
  2958.                       if actasmtoken <> AS_LBRACKET then
  2959.                         Message(assem_e_syn_start_with_bracket)
  2960.                       else
  2961.                       Begin
  2962.                         initAsmRef(instr);
  2963.                         instr.operands[operandnum].ref.segment := findsegment(tempstr);
  2964.                         BuildBracketExpression(instr,false);
  2965.                       end;
  2966.                    end
  2967.                    { // Simple register // }
  2968.                    else if (actasmtoken = AS_SEPARATOR) or (actasmtoken = AS_COMMA) then
  2969.                    Begin
  2970.                         if not (instr.operands[operandnum].operandtype in [OPR_NONE,OPR_REGISTER]) then
  2971.                          Message(assem_e_invalid_operand_type);
  2972.                         instr.operands[operandnum].operandtype := OPR_REGISTER;
  2973.                         instr.operands[operandnum].reg := findregister(tempstr);
  2974.                    end
  2975.                    else
  2976.                     Message1(assem_e_syn_register,tempstr);
  2977.                  end;
  2978.     { // a variable reference, register ref. or a constant reference // }
  2979.      AS_LBRACKET: Begin
  2980.                    BuildBracketExpression(instr,false);
  2981.                  end;
  2982.     { // Unsupported // }
  2983.      AS_SEG,AS_OFFSET: Begin
  2984.                          Message(assem_e_SEG_and_OFFSET_not_supported);
  2985.                          Consume(actasmtoken);
  2986.                          { error recovery }
  2987.                          While not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  2988.                            Consume(actasmtoken);
  2989.                        end;
  2990.      AS_SEPARATOR, AS_COMMA: ;
  2991.     else
  2992.       Message(assem_e_syn_opcode_operand);
  2993.   end; { end case }
  2994.  end;
  2995.  
  2996.  
  2997.   Procedure BuildConstant(maxvalue: longint);
  2998.   {*********************************************************************}
  2999.   { PROCEDURE BuildConstant                                             }
  3000.   {  Description: This routine takes care of parsing a DB,DD,or DW      }
  3001.   {  line and adding those to the assembler node. Expressions, range-   }
  3002.   {  checking are fullly taken care of.                                 }
  3003.   {   maxvalue: $ff -> indicates that this is a DB node.                }
  3004.   {             $ffff -> indicates that this is a DW node.              }
  3005.   {             $ffffffff -> indicates that this is a DD node.          }
  3006.   {*********************************************************************}
  3007.   { EXIT CONDITION:  On exit the routine should point to AS_SEPARATOR.  }
  3008.   {*********************************************************************}
  3009.   var
  3010.    strlength: byte;
  3011.    expr: string;
  3012.    value : longint;
  3013.   Begin
  3014.       strlength := 0; { assume it is a DB }
  3015.       Repeat
  3016.         Case actasmtoken of
  3017.           AS_STRING: Begin
  3018.                       if maxvalue = $ffff then
  3019.                          strlength := 2
  3020.                       else if maxvalue = $ffffffff then
  3021.                          strlength := 4;
  3022.                       if strlength <> 0 then
  3023.                       { DD and DW cases }
  3024.                       Begin
  3025.                          if Not PadZero(actasmpattern,strlength) then
  3026.                           Message(scan_f_string_exceeds_line);
  3027.                       end;
  3028.                       expr := actasmpattern;
  3029.                       Consume(AS_STRING);
  3030.                       Case actasmtoken of
  3031.                        AS_COMMA: Consume(AS_COMMA);
  3032.                        AS_SEPARATOR: ;
  3033.                       else
  3034.                        Message(assem_e_invalid_string_expression);
  3035.                       end; { end case }
  3036.                       ConcatString(p,expr);
  3037.                     end;
  3038.           AS_INTNUM,AS_BINNUM,
  3039.           AS_OCTALNUM,AS_HEXNUM:
  3040.                     Begin
  3041.                       value:=BuildExpression;
  3042.                       ConcatConstant(p,value,maxvalue);
  3043.                     end;
  3044.           AS_ID:
  3045.                      Begin
  3046.                       value:=BuildExpression;
  3047.                       if value > maxvalue then
  3048.                       Begin
  3049.                          Message(assem_e_expression_out_of_bounds);
  3050.                          { assuming a value of maxvalue }
  3051.                          value := maxvalue;
  3052.                       end;
  3053.                       ConcatConstant(p,value,maxvalue);
  3054.                   end;
  3055.           { These terms can start an assembler expression }
  3056.           AS_PLUS,AS_MINUS,AS_LPAREN,AS_NOT: Begin
  3057.                                           value := BuildExpression;
  3058.                                           ConcatConstant(p,value,maxvalue);
  3059.                                          end;
  3060.           AS_COMMA:  BEGIN
  3061.                        Consume(AS_COMMA);
  3062.                      END;
  3063.           AS_SEPARATOR: ;
  3064.  
  3065.         else
  3066.          Begin
  3067.            Message(assem_f_internal_error_in_buildconstant);
  3068.          end;
  3069.     end; { end case }
  3070.    Until actasmtoken = AS_SEPARATOR;
  3071.   end;
  3072.  
  3073.  
  3074.  
  3075.  
  3076.  
  3077.  
  3078.   Procedure BuildOpCode;
  3079.   {*********************************************************************}
  3080.   { PROCEDURE BuildOpcode;                                              }
  3081.   {  Description: Parses the intel opcode and operands, and writes it   }
  3082.   {  in the TInstruction object.                                        }
  3083.   {*********************************************************************}
  3084.   { EXIT CONDITION:  On exit the routine should point to AS_SEPARATOR.  }
  3085.   { On ENTRY: Token should point to AS_OPCODE                           }
  3086.   {*********************************************************************}
  3087.   var asmtok: tasmop;
  3088.       op: tasmop;
  3089.       expr: string;
  3090.       segreg: tregister;
  3091.   Begin
  3092.     expr := '';
  3093.     asmtok := A_NONE; { assmume no prefix          }
  3094.     segreg := R_NO;   { assume no segment override }
  3095.  
  3096.     { //  prefix seg opcode               // }
  3097.     { //  prefix opcode                   // }
  3098.     if findprefix(actasmpattern,asmtok) then
  3099.     Begin
  3100.      { standard opcode prefix }
  3101.      if asmtok <> A_NONE then
  3102.        instr.addprefix(asmtok);
  3103.      Consume(AS_OPCODE);
  3104.      if findoverride(actasmpattern,segreg) then
  3105.      Begin
  3106.        Consume(AS_OPCODE);
  3107.        Message(assem_w_repeat_prefix_and_seg_override);
  3108.      end;
  3109.     end
  3110.     else
  3111.     { //  seg prefix opcode               // }
  3112.     { //  seg opcode                      // }
  3113.     if findoverride(actasmpattern,segreg) then
  3114.     Begin
  3115.       Consume(AS_OPCODE);
  3116.       if findprefix(actasmpattern,asmtok) then
  3117.       Begin
  3118.      { standard opcode prefix }
  3119.         Message(assem_w_repeat_prefix_and_seg_override);
  3120.         if asmtok <> A_NONE then
  3121.           instr.addprefix(asmtok);
  3122.         Consume(AS_OPCODE);
  3123.       end;
  3124.     end;
  3125.     { //  opcode                          // }
  3126.     if (actasmtoken <> AS_OPCODE) then
  3127.     Begin
  3128.       Message(assem_e_invalid_or_missing_opcode);
  3129.       { error recovery }
  3130.       While not (actasmtoken in [AS_SEPARATOR,AS_COMMA]) do
  3131.          Consume(actasmtoken);
  3132.       exit;
  3133.     end
  3134.     else
  3135.     Begin
  3136.       op := findopcode(actasmpattern);
  3137.       instr.addinstr(op);
  3138.       { // Valid combination of prefix and instruction ? // }
  3139.       if (asmtok <> A_NONE) and (NOT CheckPrefix(asmtok,op)) then
  3140.         Message1(assem_e_invalid_prefix_and_opcode,actasmpattern);
  3141.       { // Valid combination of segment override // }
  3142.       if (segreg <> R_NO) and (NOT CheckOverride(segreg,instr)) then
  3143.         Message1(assem_e_invalid_override_and_opcode,actasmpattern);
  3144.       Consume(AS_OPCODE);
  3145.       { // Zero operand opcode ? // }
  3146.       if actasmtoken = AS_SEPARATOR then
  3147.         exit
  3148.       else
  3149.        operandnum := 1;
  3150.     end;
  3151.  
  3152.     While actasmtoken <> AS_SEPARATOR do
  3153.     Begin
  3154.        case actasmtoken of
  3155.          { //  Operand delimiter // }
  3156.          AS_COMMA: Begin
  3157.                   if operandnum > MaxOperands then
  3158.                     Message(assem_e_too_many_operands)
  3159.                   else
  3160.                     Inc(operandnum);
  3161.                   Consume(AS_COMMA);
  3162.                 end;
  3163.          { // Typecast, Constant Expression, Type Specifier // }
  3164.          AS_DWORD,AS_BYTE,AS_WORD,AS_TBYTE,AS_QWORD: Begin
  3165.                                   Case actasmtoken of
  3166.                                    AS_DWORD: instr.operands[operandnum].size := S_L;
  3167.                                    AS_WORD:  instr.operands[operandnum].size := S_W;
  3168.                                    AS_BYTE:  instr.operands[operandnum].size := S_B;
  3169.                                    AS_QWORD: instr.operands[operandnum].size := S_Q;
  3170.                                    AS_TBYTE: instr.operands[operandnum].size := S_X;
  3171.                                   end;
  3172.                                   Consume(actasmtoken);
  3173.                                   Case actasmtoken of
  3174.                                   { // Reference // }
  3175.                                   AS_PTR: Begin
  3176.                                            initAsmRef(instr);
  3177.                                            Consume(AS_PTR);
  3178.                                            BuildOperand(instr);
  3179.                                          end;
  3180.                                   { // Possibly a typecast or a constant // }
  3181.                                   { // expression.                       // }
  3182.                                   AS_LPAREN: Begin
  3183.                                               if actasmtoken = AS_ID then
  3184.                                               Begin
  3185.                                                 { Case vartype of                }
  3186.                                                 {  LOCAL: Replace by offset and  }
  3187.                                                 {         BP in treference.      }
  3188.                                                 {  GLOBAL: Replace by mangledname}
  3189.                                                 {    in symbol of treference     }
  3190.                                                 { Check if next token = RPAREN   }
  3191.                                                 { otherwise syntax error.        }
  3192.                                                 initAsmRef(instr);
  3193.                                                 if not CreateVarInstr(instr,actasmpattern,
  3194.                                                    operandnum) then
  3195.                                                 Begin
  3196.                                                    Message1(assem_e_unknown_id,actasmpattern);
  3197.                                                 end;
  3198.                                               end
  3199.                                               else
  3200.                                                begin
  3201.                                                  instr.operands[operandnum].operandtype := OPR_CONSTANT;
  3202.                                                  instr.operands[operandnum].val := BuildExpression;
  3203.                                                end;
  3204.                                             end;
  3205.                                   else
  3206.                                     BuildOperand(instr);
  3207.                                   end; { end case }
  3208.                             end;
  3209.          { // Type specifier // }
  3210.          AS_NEAR,AS_FAR: Begin
  3211.                           if actasmtoken = AS_NEAR then
  3212.                             Message(assem_w_near_ignored)
  3213.                           else
  3214.                             Message(assem_w_far_ignored);
  3215.                           Consume(actasmtoken);
  3216.                           if actasmtoken = AS_PTR then
  3217.                            begin
  3218.                              initAsmRef(instr);
  3219.                              Consume(AS_PTR);
  3220.                            end;
  3221.                            BuildOperand(instr);
  3222.                        end;
  3223.          { // End of asm operands for this opcode // }
  3224.          AS_SEPARATOR: ;
  3225.          { // Constant expression // }
  3226.          AS_LPAREN: Begin
  3227.                       instr.operands[operandnum].operandtype := OPR_CONSTANT;
  3228.                       instr.operands[operandnum].val := BuildExpression;
  3229.                     end;
  3230.        else
  3231.          BuildOperand(instr);
  3232.      end; { end case }
  3233.     end; { end while }
  3234.   end;
  3235.  
  3236.  
  3237.   Function Assemble: Ptree;
  3238.   {*********************************************************************}
  3239.   { PROCEDURE Assemble;                                                 }
  3240.   {  Description: Parses the intel assembler syntax, parsing is done    }
  3241.   {  according to the rules in the Turbo Pascal manual.                 }
  3242.   {*********************************************************************}
  3243.   Var
  3244.    hl: plabel;
  3245.    labelptr: pasmlabel;
  3246.   Begin
  3247.     Message(assem_d_start_intel);
  3248.     inexpression := FALSE;
  3249.     firsttoken := TRUE;
  3250.     operandnum := 0;
  3251.     { sets up all opcode and register tables in uppercase }
  3252.     if not _asmsorted then
  3253.     Begin
  3254.       SetupTables;
  3255.       _asmsorted := TRUE;
  3256.     end;
  3257.     p:=new(paasmoutput,init);
  3258.     { setup label linked list }
  3259.     labellist.init;
  3260.     c:=asmgetchar;
  3261.     actasmtoken:=gettoken;
  3262.     while actasmtoken<>AS_END do
  3263.     Begin
  3264.       case actasmtoken of
  3265.         AS_LLABEL: Begin
  3266.                     labelptr := labellist.search(actasmpattern);
  3267.                     if not assigned(labelptr) then
  3268.                     Begin
  3269.                         getlabel(hl);
  3270.                         labellist.insert(actasmpattern,hl,TRUE);
  3271.                         ConcatLabel(p,A_LABEL,hl);
  3272.                     end
  3273.                     else
  3274.                     { the label has already been inserted into the  }
  3275.                     { label list, either as an intruction label (in }
  3276.                     { this case it has not been emitted), or as a   }
  3277.                     { duplicate local symbol (in this case it has   }
  3278.                     { already been emitted).                        }
  3279.                     Begin
  3280.                        if labelptr^.emitted then
  3281.                         Message1(assem_e_dup_local_sym,'@'+labelptr^.name^)
  3282.                        else
  3283.                         Begin
  3284.                           if assigned(labelptr^.lab) then
  3285.                             ConcatLabel(p,A_LABEL,labelptr^.lab);
  3286.                           labelptr^.emitted := TRUE;
  3287.                         end;
  3288.                     end;
  3289.                     Consume(AS_LLABEL);
  3290.                   end;
  3291.         AS_LABEL: Begin
  3292.                      if SearchLabel(actasmpattern,hl) then
  3293.                        ConcatLabel(p,A_LABEL, hl)
  3294.                      else
  3295.                        Message1(assem_e_unknown_label_identifer,actasmpattern);
  3296.                      Consume(AS_LABEL);
  3297.                  end;
  3298.         AS_DW:    Begin
  3299.                    Consume(AS_DW);
  3300.                    BuildConstant($ffff);
  3301.                  end;
  3302.  
  3303.         AS_DB:   Begin
  3304.                   Consume(AS_DB);
  3305.                   BuildConstant($ff);
  3306.                 end;
  3307.         AS_DD:   Begin
  3308.                  Consume(AS_DD);
  3309.                  BuildConstant($ffffffff);
  3310.                 end;
  3311.         AS_OPCODE: Begin
  3312.                    instr.init;
  3313.                    BuildOpcode;
  3314.                    instr.numops := operandnum;
  3315.                    if instr.labeled then
  3316.                      ConcatLabeledInstr(instr)
  3317.                    else
  3318.                      ConcatOpCode(instr);
  3319.                   end;
  3320.         AS_SEPARATOR:Begin
  3321.                      Consume(AS_SEPARATOR);
  3322.                      { let us go back to the first operand }
  3323.                      operandnum := 0;
  3324.                     end;
  3325.         AS_END: ; { end assembly block }
  3326.     else
  3327.       Begin
  3328.          Message(assem_e_assemble_node_syntax_error);
  3329.          { error recovery }
  3330.          Consume(actasmtoken);
  3331.       end;
  3332.     end; { end case }
  3333.   end; { end while }
  3334.   { check if there were undefined symbols.   }
  3335.   { if so, then list each of those undefined }
  3336.   { labels.                                  }
  3337.   if assigned(labellist.First) then
  3338.   Begin
  3339.     labelptr := labellist.First;
  3340.     if labellist.First <> nil then
  3341.     Begin
  3342.       { first label }
  3343.       if not labelptr^.emitted then
  3344.        Message1(assem_e_unknown_local_sym,'@'+labelptr^.name^);
  3345.       { other labels ... }
  3346.       While (labelptr^.Next <> nil) do
  3347.        Begin
  3348.           labelptr := labelptr^.Next;
  3349.           if not labelptr^.emitted then
  3350.            Message1(assem_e_unknown_local_sym,'@'+labelptr^.name^);
  3351.       end;
  3352.     end;
  3353.   end;
  3354.   assemble := genasmnode(p);
  3355.   labellist.done;
  3356.   Message(assem_d_finish_intel);
  3357. end;
  3358.  
  3359.  
  3360. Begin
  3361.    old_exit:=exitproc;
  3362.    exitproc:=@rai386_exit;
  3363. end.
  3364. {
  3365.   $Log: rai386.pas,v $
  3366.   Revision 1.2.2.1  1998/05/25 22:58:50  carl
  3367.     * single operand bugfixes
  3368.  
  3369.   Revision 1.2  1998/03/31 15:21:01  florian
  3370.     * fix of out (intel syntax) applied
  3371.  
  3372.   Revision 1.1.1.1  1998/03/25 11:18:15  root
  3373.   * Restored version
  3374.  
  3375.   Revision 1.19  1998/03/24 21:48:34  florian
  3376.     * just a couple of fixes applied:
  3377.          - problem with fixed16 solved
  3378.          - internalerror 10005 problem fixed
  3379.          - patch for assembler reading
  3380.          - small optimizer fix
  3381.          - mem is now supported
  3382.  
  3383.   Revision 1.18  1998/03/10 01:17:26  peter
  3384.     * all files have the same header
  3385.     * messages are fully implemented, EXTDEBUG uses Comment()
  3386.     + AG... files for the Assembler generation
  3387.  
  3388.   Revision 1.17  1998/03/09 12:58:12  peter
  3389.     * FWait warning is only showed for Go32V2 and $E+
  3390.     * opcode tables moved to i386.pas/m68k.pas to reduce circular uses (and
  3391.       for m68k the same tables are removed)
  3392.     + $E for i386
  3393.  
  3394.   Revision 1.16  1998/03/04 17:33:56  michael
  3395.   + Changed ifdef FPK to ifdef FPC
  3396.  
  3397.   Revision 1.15  1998/03/03 22:38:26  peter
  3398.     * the last 3 files
  3399.  
  3400.   Revision 1.14  1998/03/02 01:49:15  peter
  3401.     * renamed target_DOS to target_GO32V1
  3402.     + new verbose system, merged old errors and verbose units into one new
  3403.       verbose.pas, so errors.pas is obsolete
  3404.  
  3405.   Revision 1.13  1998/02/13 10:35:38  daniel
  3406.   * Made Motorola version compilable.
  3407.   * Fixed optimizer
  3408.  
  3409.   Revision 1.12  1998/02/12 11:50:36  daniel
  3410.   Yes! Finally! After three retries, my patch!
  3411.  
  3412.   Changes:
  3413.  
  3414.   Complete rewrite of psub.pas.
  3415.   Added support for DLL's.
  3416.   Compiler requires less memory.
  3417.   Platform units for each platform.
  3418.  
  3419.   Revision 1.11  1998/02/07 18:02:36  carl
  3420.     + fwait warning for emulation
  3421.  
  3422.   Revision 1.10  1998/01/19 03:11:40  carl
  3423.     * bugfix number 78
  3424.  
  3425.   Revision 1.9  1998/01/09 19:22:51  carl
  3426.   * bugfix of __ID variable names
  3427.  
  3428.   Revision 1.8  1997/12/09 14:00:25  carl
  3429.   * bugfix of intr reg,reg instructions, size must always be specified
  3430.     under gas (ref: DJGPP FAQ)
  3431.   * bugfix of concatopcode with fits init twice!
  3432.   + unknown instr. only poermitted when compiling system unit and/or
  3433.     target processor > i386
  3434.  
  3435.   Revision 1.7  1997/12/04 12:20:50  pierre
  3436.     +* MMX instructions added to att output with a warning that
  3437.        GNU as version >= 2.81 is needed
  3438.        bug in reading of reals under att syntax corrected
  3439.  
  3440.   Revision 1.6  1997/11/28 18:14:45  pierre
  3441.    working version with several bug fixes
  3442.  
  3443.   Revision 1.5  1997/11/28 15:43:20  florian
  3444.   Fixed stack ajustment bug, 0.9.8 compiles now 0.9.8 without problems.
  3445.  
  3446.   Revision 1.4  1997/11/28 15:31:59  carl
  3447.   * uncommented firstop and lastop. (otherwise can cause bugs)
  3448.  
  3449.   Revision 1.3  1997/11/28 14:26:22  florian
  3450.   Fixed some bugs
  3451.  
  3452.   Revision 1.2  1997/11/28 12:03:53  michael
  3453.   Changed comment delimiters to braces, causes problems with 0.9.1
  3454.   Changed use of ord to typecast with longint.
  3455.   Made boolean expressions non-redundant.
  3456.  
  3457.   Revision 1.1.1.1  1997/11/27 08:33:00  michael
  3458.   FPC Compiler CVS start
  3459.  
  3460.  
  3461.   Pre-CVS log:
  3462.  
  3463.   CEC   Carl-Eric Codere
  3464.   FK    Florian Klaempfl
  3465.   PM    Pierre Muller
  3466.   +     feature added
  3467.   -     removed
  3468.   *     bug fixed or changed
  3469.  
  3470.   9th november 1997:
  3471.    + first working version with main distribution line of FPC (CEC)
  3472.  12th november 1997:
  3473.    * bugfix of CALL and JMP with symbolic references. (CEC)
  3474.  13th november 1997:
  3475.    * too many bugfixes/improvements to name... (CEC)
  3476.    * Fixed range check, line numbering, missing operand checking
  3477.      bugs - range checking must be off to compile under tp. (CEC)
  3478.    + speed improvement of 30% over old version with global look up tables.
  3479.  14th november 1997:
  3480.    + added support for record/object offsets. (CEC)
  3481.    * fixed bug regarding ENTER and push imm8 instruction(CEC)
  3482.    + fixed conflicts with fpu instructions. (CEC).
  3483.  
  3484. }
  3485.